diff --git a/.gitignore b/.gitignore index cb2789f9b..77df2c1c5 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ /public/react/node_modules/ /public/react/config/stats.json /public/react/stats.json +/public/react/.idea/* /public/npm-debug.log @@ -58,6 +59,7 @@ vendor/bundle/ .ruby-version .ruby-gemset +/Users /files /public/images/avatars /public/files diff --git a/Gemfile b/Gemfile index 7cda93671..28df2328c 100644 --- a/Gemfile +++ b/Gemfile @@ -95,3 +95,4 @@ gem 'bulk_insert' gem 'searchkick' gem 'aasm' +gem 'enumerize' diff --git a/Gemfile.lock b/Gemfile.lock index a33cd2ef6..6a4a7e08f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -54,8 +54,8 @@ GEM tzinfo (~> 1.1) acts-as-taggable-on (6.0.0) activerecord (~> 5.0) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) + addressable (2.7.0) + public_suffix (>= 2.0.2, < 5.0) archive-zip (0.11.0) io-like (~> 0.3.0) arel (9.0.0) @@ -106,6 +106,8 @@ GEM elasticsearch-transport (7.2.0) faraday multi_json + enumerize (2.3.1) + activesupport (>= 3.2) erubi (1.7.1) execjs (2.7.0) faraday (0.15.4) @@ -178,7 +180,7 @@ GEM rack (>= 1.2, < 3) pdfkit (0.8.4.1) popper_js (1.14.5) - public_suffix (3.0.2) + public_suffix (4.0.1) puma (3.12.0) rack (2.0.5) rack-cors (1.0.2) @@ -366,6 +368,7 @@ DEPENDENCIES byebug capybara (>= 2.15, < 4.0) chromedriver-helper + enumerize faraday (~> 0.15.4) font-awesome-sass (= 4.7.0) gitlab! diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index e7a4d28ff..f882a9b36 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -13,10 +13,14 @@ //= require bootstrap-datepicker //= require bootstrap.viewer //= require jquery.mloading +//= require common //= require echarts -//= require lib/codemirror -//= require mode/shell/shell +//= require codemirror/lib/codemirror +//= require codemirror/mode/shell/shell +//= require editormd/editormd +//= require editormd/languages/zh-tw +//= require dragula/dragula //= require_tree ./i18n //= require_tree ./admins @@ -40,8 +44,16 @@ $.notifyDefaults({ delay: 2000 }); +function show_success_flash(){ + $.notify({ + message: '操作成功' + },{ + type: 'success' + }); +} + $(document).on('turbolinks:load', function(){ - $('[data-toggle="tooltip"]').tooltip(); + $('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); $('[data-toggle="popover"]').popover(); // 图片查看大图 diff --git a/app/assets/javascripts/admins/about.js b/app/assets/javascripts/admins/about.js new file mode 100644 index 000000000..d706e653c --- /dev/null +++ b/app/assets/javascripts/admins/about.js @@ -0,0 +1,5 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-abouts-edit-page, body.admins-abouts-update-page').length > 0) { + createMDEditor('about-us-editor', {}); + } +}) \ No newline at end of file diff --git a/app/assets/javascripts/admins/agreement.js b/app/assets/javascripts/admins/agreement.js new file mode 100644 index 000000000..387d4b337 --- /dev/null +++ b/app/assets/javascripts/admins/agreement.js @@ -0,0 +1,5 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-agreements-edit-page, body.admins-agreements-update-page').length > 0) { + createMDEditor('agreement-editor', {}); + } +}) \ No newline at end of file diff --git a/app/assets/javascripts/admins/auth_schools/index.js b/app/assets/javascripts/admins/auth_schools/index.js new file mode 100644 index 000000000..924a1a73e --- /dev/null +++ b/app/assets/javascripts/admins/auth_schools/index.js @@ -0,0 +1,6 @@ + +function show_add_manager(id) { + $(".auth-schools-user-add").modal("show"); + + $(".auth-schools-user-add").find("#school_id_input").val(id) +} \ No newline at end of file diff --git a/app/assets/javascripts/admins/cooperatives.js b/app/assets/javascripts/admins/cooperatives.js new file mode 100644 index 000000000..f650e00e3 --- /dev/null +++ b/app/assets/javascripts/admins/cooperatives.js @@ -0,0 +1,96 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-cooperatives-index-page').length > 0) { + // ------------ 保存链接 ----------- + $('.coo-img-card').on('click', '.save-url-btn', function(){ + var $link = $(this); + var cooId = $link.data('id'); + var url = $('.coo-img-item-' + cooId).find('.url-input').val(); + $link.attr('disabled', true); + + $.ajax({ + url: '/admins/cooperatives/' + cooId, + method: 'PATCH', + dataType: 'json', + data: { url: url }, + success: function(data){ + $.notify({ message: '保存成功' }); + }, + error: ajaxErrorNotifyHandler, + complete: function(){ + $link.removeAttr('disabled'); + } + }) + }); + + // ------------ 拖拽 ------------- + var onDropFunc = function(el, _target, _source, sibling){ + var moveId = $(el).data('id'); + var insertId = $(sibling).data('id') || ''; + + $.ajax({ + url: '/admins/cooperatives/drag', + method: 'POST', + dataType: 'json', + data: { move_id: moveId, after_id: insertId }, + success: function(data){ + }, + error: function(res){ + var data = res.responseJSON; + $.notify({message: '移动失败,原因:' + data.message}, {type: 'danger'}); + } + }) + }; + var ele1 = document.getElementById('coo-img-container-alliance_coop'); + dragula([ele1], { mirrorContainer: ele1 }).on('drop', onDropFunc); + var ele2 = document.getElementById('coo-img-container-com_coop'); + dragula([ele2], { mirrorContainer: ele2 }).on('drop', onDropFunc); + var ele3 = document.getElementById('coo-img-container-edu_coop'); + dragula([ele3], { mirrorContainer: ele3 }).on('drop', onDropFunc); + + + // ----------- 新增 -------------- + var $createModal = $('.modal.admin-add-cooperative-modal'); + var $createForm = $createModal.find('form.admin-add-cooperative-form'); + + $createForm.validate({ + errorElement: 'span', + errorClass: 'danger text-danger', + rules: { + "coo_img[image]": { + required: true + } + } + }); + + $createModal.on('show.bs.modal', function(event){ + resetFileInputFunc($createModal.find('.img-file-input')); + $createModal.find('.file-names').html('选择文件'); + + var $link = $(event.relatedTarget); + var imgType = $link.data('imgType'); + $createForm.find('input[name="coo_img[img_type]"]').val(imgType); + }); + + $createModal.on('click', '.submit-btn', function() { + $createForm.find('.error').html(''); + + if ($createForm.valid()) { + $createForm.submit(); + } else { + $createForm.find('.error').html('请选择图片'); + } + }); + $createModal.on('change', '.img-file-input', function(){ + var file = $(this)[0].files[0]; + $createModal.find('.file-names').html(file ? file.name : '请选择文件'); + }) + + // -------------- 重新上传图片 -------------- + //replace_image_url + $('.modal.admin-upload-file-modal').on('upload:success', function(e, data){ + var $cooImgItem = $('.coo-img-item-' + data.source_id); + $.post('/admins/cooperatives/'+ data.source_id + '/replace_image_url'); + $cooImgItem.find('.coo-img-item-img img').attr('src', data.url); + }) + } +}) \ No newline at end of file diff --git a/app/assets/javascripts/admins/department_applies/index.js b/app/assets/javascripts/admins/department_applies/index.js deleted file mode 100644 index 7ecf0be75..000000000 --- a/app/assets/javascripts/admins/department_applies/index.js +++ /dev/null @@ -1,22 +0,0 @@ -$(document).on('turbolinks:load', function() { - var $editModal = $('.department-apply-edit-modal'); - if($editModal.length > 0){ - var $form = $editModal.find('form.department-apply-form'); - var $applyIdInput = $form.find('input[name="id"]'); - $editModal.on('show.bs.modal', function (event) { - var $link = $(event.relatedTarget); - var applyId = $link.data('id'); - $applyIdInput.val(applyId); - }); - $editModal.on('click', '.submit-btn', function(){ - $.ajax({ - method: "PUT", - dataType: 'script', - url: "/admins/department_applies/"+ $applyIdInput.val(), - data: $form.serialize(), - }).done(function(){ - $editModal.modal('hide'); - }); - }); - } -}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/ec_templates/index.js b/app/assets/javascripts/admins/ec_templates/index.js new file mode 100644 index 000000000..88ac29f58 --- /dev/null +++ b/app/assets/javascripts/admins/ec_templates/index.js @@ -0,0 +1,70 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-ec-templates-index-page').length > 0) { + var add_modal = $(".ec-templates-new-add"); + var template_file_name = add_modal.find(".template-file-upload"); + var attachment_id_input = add_modal.find(".template_attachment_id"); + var template_container = $(".ec-templates-list-container"); + + //编辑附件 + template_container.on("click", ".edit-template-content", function () { + var t_id = $(this).attr("data-id"); + var t_name = $(this).attr("data-name"); + var template_name = $(this).attr("data-template-name"); + var t_msg = $(this).attr("data-msg"); + var template_id = $(this).attr("data-template-id"); + add_modal.modal("show"); + add_modal.find(".template_add_title").html(t_msg); + attachment_id_input.val(template_id); + add_modal.find(".template_show_id").val(t_id); + add_modal.find("input[name='name']").val(t_name); + add_modal.find("i.delete-template-icon").attr("data-id", template_id); + if(template_id !== "-1"){ + template_file_name.find("span.template-file-input").hide(); + template_file_name.find("span.template_file_show").show(); + template_file_name.find("span.template_file_show_title").html(template_name); + } + }); + + + //删除附件 + add_modal.on("click",".delete-template-icon",function () { + var attachment_id = $(this).attr("data-id"); + $.ajax({ + url: "/api/attachments/" + attachment_id, + type: "delete", + contentType:"application/json", + dataType:"json", + success: function (data) { + template_file_name.find("span.template-file-input").show(); + template_file_name.find("span.template_file_show").hide(); + attachment_id_input.attr("value","-1") + } + }) + }); + + //上传附件 + add_modal.on("change", "#upload_template_file",function () { + + var template = document.getElementById('upload_template_file').files[0]; + + var file_content = new FormData(); + + file_content.append("file", template); + + $.ajax({ + type: "POST", + url: "/api/attachments", + data:file_content, + contentType: false, + processData: false, + success: function (data) { + template_file_name.find("span.template-file-input").hide(); + template_file_name.find("span.template_file_show").show(); + template_file_name.find("span.template_file_show_title").html(template.name); + template_file_name.find("i.delete-template-icon").attr("data-id",data.id); + attachment_id_input.val(data.id) + } + }) + }) + } +}); diff --git a/app/assets/javascripts/admins/graduation_standards/index.js b/app/assets/javascripts/admins/graduation_standards/index.js new file mode 100644 index 000000000..c5b1c2da5 --- /dev/null +++ b/app/assets/javascripts/admins/graduation_standards/index.js @@ -0,0 +1,13 @@ +$(document).on('turbolinks:load', function() { + if($(".admins-graduation-standards-index-page").length > 0){ + $(".admin-body-container").on("click", ".standard-create-modal", function () { + var content = $(this).attr("data-content"); + var g_id = $(this).attr("data-id"); + var g_msg = $(this).attr("data-msg"); + + $("#graduation-modal-type").html(g_msg); + $("#graduation_standard_id").val(g_id); + $("textarea[name='content']").val(content); + }) + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/help-center.js b/app/assets/javascripts/admins/help-center.js new file mode 100644 index 000000000..5fd6055df --- /dev/null +++ b/app/assets/javascripts/admins/help-center.js @@ -0,0 +1,5 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-help-centers-edit-page, body.admins-help-centers-update-page').length > 0) { + createMDEditor('help-center-editor', {}); + } +}) \ No newline at end of file diff --git a/app/assets/javascripts/admins/major_informations/index.js b/app/assets/javascripts/admins/major_informations/index.js new file mode 100644 index 000000000..f0ab9c5f5 --- /dev/null +++ b/app/assets/javascripts/admins/major_informations/index.js @@ -0,0 +1,13 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-major-informations-index-page').length > 0) { + var box_contain = $(".major-informations-list-container"); + box_contain.on("click",".collapse-item",function () { + var a_fa = $(this).find("i"); + if(a_fa.hasClass("fa-caret-right")){ + a_fa.removeClass("fa-caret-right").addClass("fa-caret-down"); + }else{ + a_fa.removeClass("fa-caret-down").addClass("fa-caret-right"); + } + }); + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/modals/admin-merge-department-modal.js b/app/assets/javascripts/admins/modals/admin-merge-department-modal.js index aead3f485..f5f2dceeb 100644 --- a/app/assets/javascripts/admins/modals/admin-merge-department-modal.js +++ b/app/assets/javascripts/admins/modals/admin-merge-department-modal.js @@ -66,10 +66,11 @@ $(document).on('turbolinks:load', function() { var $link = $(event.relatedTarget); var schoolId = $link.data('schoolId'); + var url = $link.data('url'); $schoolIdInput.val(schoolId); $originDepartmentIdInput.val($link.data('departmentId')); - + $form.data('url', url); $.ajax({ url: '/api/schools/' + schoolId + '/departments/for_option.json', dataType: 'json', diff --git a/app/assets/javascripts/admins/users/index.js b/app/assets/javascripts/admins/users/index.js index 1ac936df5..c7b8e5e6a 100644 --- a/app/assets/javascripts/admins/users/index.js +++ b/app/assets/javascripts/admins/users/index.js @@ -122,10 +122,6 @@ $(document).on('turbolinks:load', function(){ // 导入学生 var $importUserModal = $('.modal.admin-import-user-modal'); var $importUserForm = $importUserModal.find('form.admin-import-user-form') - var resetFileInputFunc = function(file){ - file.after(file.clone().val("")); - file.remove(); - } $importUserModal.on('show.bs.modal', function(){ resetFileInputFunc($importUserModal.find('.upload-file-input')); diff --git a/app/assets/javascripts/common.js b/app/assets/javascripts/common.js new file mode 100644 index 000000000..dc0818b64 --- /dev/null +++ b/app/assets/javascripts/common.js @@ -0,0 +1,45 @@ +function createMDEditor(element, opts){ + var defaults = { + height: 600, + path: '/editormd/lib/', + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "image", "table", '|', "watch", "clear"] + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + dialogMaskOpacity: 0.6, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: '/api/attachments.json' + } + var options = $.extend({}, defaults, opts); + + return editormd(element, options); +} + +function ajaxErrorNotifyHandler(res) { + var message = ''; + if(res.status !== 500){ + message = res.responseJSON.message; + } else { + message = '系统错误'; + } + return $.notify({message: message}, {type: 'danger'}); +} + +function resetFileInputFunc(file){ + file.after(file.clone().val("")); + file.remove(); +} \ No newline at end of file diff --git a/app/assets/javascripts/course_stages.js b/app/assets/javascripts/course_stages.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/course_stages.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 30fd635a6..ac2e58216 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -6,7 +6,10 @@ @import "bootstrap-datepicker"; @import "bootstrap-datepicker.standalone"; @import "jquery.mloading"; -@import "lib/codemirror"; + +@import "codemirror/lib/codemirror"; +@import "editormd/css/editormd.min"; +@import "dragula/dragula"; @import "common"; @import "admins/*"; @@ -47,4 +50,4 @@ input.form-control { right:20px; position: absolute; } -.position-r{position:relative;} + diff --git a/app/assets/stylesheets/admins/auth_schools.scss b/app/assets/stylesheets/admins/auth_schools.scss new file mode 100644 index 000000000..7106f6d42 --- /dev/null +++ b/app/assets/stylesheets/admins/auth_schools.scss @@ -0,0 +1,66 @@ +.admins-auth-schools-index-page{ + .list-item-title{ + padding-bottom:5px; + padding-left: 33px; + color: #555; + } + .list-item-title-1{ + width: 100px; + display: inline-block; + } + .list-item-title-2{ + width: 200px; + display: inline-block; + } + .collegeManage{ + float: left; + padding: 0px 8px; + border-radius: 6px; + background-color: #f5f5f5; + margin: 3px 0px 3px 10px; + height: 34px; + line-height: 34px; + a{ + color: #05101a; + } + a:hover{ + color: #007bff; + } + } + i:hover{ + color: #333; + } + .add-manager-i{ + float: left; + i{ + padding: 10px 5px; + } + } + .auth-schools-new-add, .auth-schools-user-add{ + .flex-column{ + input{ + height: 38px; + } + } + .search-school{ + margin-left: 15px; + } + + } + .school-search-list{ + background: #F4FAFF; + height: 280px; + overflow-y: scroll; + padding: 10px 0; + } + .school-list-item{ + padding: 2px 10px; + input{ + font-size: 20px; + margin-right: 5px; + } + + } + + +} \ No newline at end of file diff --git a/app/assets/stylesheets/admins/cooperatives.scss b/app/assets/stylesheets/admins/cooperatives.scss new file mode 100644 index 000000000..530ed2316 --- /dev/null +++ b/app/assets/stylesheets/admins/cooperatives.scss @@ -0,0 +1,35 @@ +.admins-cooperatives-index-page { + .coo-img-card { + .coo-img-item { + & > .drag { + cursor: move; + background: #fff; + box-shadow: 1px 2px 5px 3px #f0f0f0; + } + + &-img { + cursor: pointer; + width: 100%; + height: 40px; + margin-bottom: 10px; + + & > img { + width: 100%; + height: 40px; + } + } + + .delete-btn { + position: absolute; + top: 3px; + right: 20px; + color: red; + cursor: pointer; + } + + .save-url-btn { + cursor: pointer; + } + } + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/admins/ec_tempaltes.scss b/app/assets/stylesheets/admins/ec_tempaltes.scss new file mode 100644 index 000000000..ba824b9b2 --- /dev/null +++ b/app/assets/stylesheets/admins/ec_tempaltes.scss @@ -0,0 +1,22 @@ +.admins-ec-templates-index-page{ + .template-file-upload{ + padding: 10px; + background: #fafafa; + border: 1px dashed #ccc; + text-align: center; + color: #999; + position: relative; + width: 100%; + + } + input[name='file']{ + opacity: 0; + position: absolute; + display: inline-block; + left: 0; + height: 43px; + top: 0; + width:100%; + cursor: pointer; + } +} \ No newline at end of file diff --git a/app/assets/stylesheets/admins/major_informations.scss b/app/assets/stylesheets/admins/major_informations.scss new file mode 100644 index 000000000..b5d4096e7 --- /dev/null +++ b/app/assets/stylesheets/admins/major_informations.scss @@ -0,0 +1,37 @@ +.admins-major-informations-index-page{ + .fr{ + float:right; + } + .panel-default{ + margin-bottom: 10px; + background-color: rgb(245, 245, 245); + .panel-heading{ + i{ + margin-right:15px; + font-size:16px; + color:rgb(204, 204, 204); + } + a{ + padding: 8px 10px; + display: inline-block; + width:100%; + color:rgb(102, 102, 102); + } + } + .panel-collapse{ + padding-top: 10px; + background: #fff; + table{ + text-align:center; + th,td{ + padding: 8px; + } + td{ + color:#888; + } + } + } + + } + +} \ No newline at end of file diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 3310ec828..bb40e7950 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -33,4 +33,17 @@ input.form-control { .font-12 { font-size: 12px !important; } .font-14 { font-size: 14px !important; } .font-16 { font-size: 16px !important; } -.font-18 { font-size: 18px !important; } \ No newline at end of file +.font-18 { font-size: 18px !important; } +.padding10-5 { padding: 10px 5px;} +.width100 { width: 100%;} +.mb10 { margin-bottom: 10px ;} +.mt10 { margin-top: 10px ;} +.mr10{ margin-right: 10px; } +.textarea-width-100{width:100%; resize: none; border: 1px solid #ccc;} +.padding10{padding: 10px;} +.padding5-10{padding: 5px 10px;} +.position-r{position:relative;} +.color-grey-c{color:#ccc} +.inline-block{display:inline-block;} +.hide{display: none;} +.show{display: block;} diff --git a/app/assets/stylesheets/course_stages.scss b/app/assets/stylesheets/course_stages.scss new file mode 100644 index 000000000..faa60b4b0 --- /dev/null +++ b/app/assets/stylesheets/course_stages.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the course_stages controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/admins/abouts_controller.rb b/app/controllers/admins/abouts_controller.rb new file mode 100644 index 000000000..1f5838cbb --- /dev/null +++ b/app/controllers/admins/abouts_controller.rb @@ -0,0 +1,18 @@ +class Admins::AboutsController < Admins::BaseController + def edit + current_doc + end + + def update + current_doc.update!(about_us: params[:about_us]) + + flash[:success] = '保存成功' + redirect_to edit_admins_about_path + end + + private + + def current_doc + @doc ||= Help.first || Help.create + end +end \ No newline at end of file diff --git a/app/controllers/admins/agreements_controller.rb b/app/controllers/admins/agreements_controller.rb new file mode 100644 index 000000000..2a0d56b8a --- /dev/null +++ b/app/controllers/admins/agreements_controller.rb @@ -0,0 +1,18 @@ +class Admins::AgreementsController < Admins::BaseController + def edit + current_doc + end + + def update + current_doc.update!(agreement: params[:agreement]) + + flash[:success] = '保存成功' + redirect_to edit_admins_agreement_path + end + + private + + def current_doc + @doc ||= Help.first || Help.create + end +end \ No newline at end of file diff --git a/app/controllers/admins/auth_schools_controller.rb b/app/controllers/admins/auth_schools_controller.rb new file mode 100644 index 000000000..e7c0253b6 --- /dev/null +++ b/app/controllers/admins/auth_schools_controller.rb @@ -0,0 +1,58 @@ +class Admins::AuthSchoolsController < Admins::BaseController + + def index + schools = School.where(ec_auth: 1).includes(:users).order("updated_at desc") + @params_page = params[:page] || 1 + @schools = paginate schools + end + + def destroy + ActiveRecord::Base.transaction do + school = School.where(id: params[:id]).first + school.destroy + render_success_js + end + end + + # 工程认证单位列表搜索学校 + def search_school + @schools = School.where("ec_auth != 1 and name like '%#{params[:name]}%'").limit(10) + end + + # 添加认证学校 + def add_school + all_schools = School.all + all_schools.where(id: params[:school_id]).update_all(ec_auth: 1) + schools = all_schools.where(ec_auth: 1).order("updated_at desc") + @params_page = params[:page] || 1 + @schools = paginate schools + end + + # 搜索用户 + def search_manager + school = School.find_by(id: params[:school_id]) + user_ids = school&.ec_school_users&.pluck(:user_id) + @users = User.where.not(id: user_ids).where("concat(lastname, firstname) like ?", "%#{params[:name].strip.to_s}%").limit(10) + end + + # 添加认证学校管理员 + def add_manager + ActiveRecord::Base.transaction do + user_ids = params[:user_id] + @school_id = params[:school_id] + user_ids.each do |id| + EcSchoolUser.create(user_id: id, school_id: @school_id) + end + @school_users = User.where(id: user_ids) + end + end + + # 删除学校管理员 + def remove_manager + ActiveRecord::Base.transaction do + manager = EcSchoolUser.where(school_id: params[:school_id], user_id: params[:user_id]).first + manager&.destroy + end + end + +end \ No newline at end of file diff --git a/app/controllers/admins/base_controller.rb b/app/controllers/admins/base_controller.rb index 6f89e7afa..345df3e31 100644 --- a/app/controllers/admins/base_controller.rb +++ b/app/controllers/admins/base_controller.rb @@ -5,6 +5,8 @@ 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 diff --git a/app/controllers/admins/contact_us_controller.rb b/app/controllers/admins/contact_us_controller.rb new file mode 100644 index 000000000..5c6a7b6e2 --- /dev/null +++ b/app/controllers/admins/contact_us_controller.rb @@ -0,0 +1,28 @@ +class Admins::ContactUsController < Admins::BaseController + def edit + @cooperations = Cooperation.all.group(:user_type) + @help = Help.first + end + + def update + cooperation = Cooperation.find(params[:id]) + cooperation.update!(update_cooperation_params) + + flash[:success] = '保存成功' + redirect_to edit_admins_contact_us_path + end + + def update_address + help = Help.first || Help.create + help.update!(status: params.dig('help', 'status')) + + flash[:success] = '保存成功' + redirect_to edit_admins_contact_us_path + end + + private + + def update_cooperation_params + params.require(:cooperation).permit(:name, :qq, :mail) + end +end \ No newline at end of file diff --git a/app/controllers/admins/cooperatives_controller.rb b/app/controllers/admins/cooperatives_controller.rb new file mode 100644 index 000000000..4c114003e --- /dev/null +++ b/app/controllers/admins/cooperatives_controller.rb @@ -0,0 +1,84 @@ +class Admins::CooperativesController < Admins::BaseController + before_action :convert_file!, only: [:create] + + def index + @data = { 'alliance_coop' => [], 'com_coop' => [], 'edu_coop' => [] } + @data = @data.merge CooImg.all.group_by(&:img_type) + end + + def create + position = CooImg.where(img_type: create_params[:img_type]).count + 1 + + ActiveRecord::Base.transaction do + coo = CooImg.create!(create_params.merge(position: position)) + + file_path = Util::FileManage.disk_filename('CooImg', coo.id) + File.delete(file_path) if File.exist?(file_path) # 删除之前的文件 + Util.write_file(@file, file_path) + + coo.update!(url_states: Util::FileManage.disk_file_url('CooImg', coo.id)) + end + + flash[:success] = '保存成功' + redirect_to admins_cooperatives_path + end + + def update + current_coo.update!(src_states: params[:url]) + render_ok + end + + def destroy + ActiveRecord::Base.transaction do + current_coo.destroy! + # 前移 + CooImg.where(img_type: current_coo.img_type).where('position > ?', current_coo.position) + .update_all('position = position - 1') + + file_path = Util::FileManage.disk_filename('CooImg', current_coo.id) + File.delete(file_path) if File.exist?(file_path) + end + render_delete_success + end + + def drag + move = CooImg.find_by(id: params[:move_id]) + after = CooImg.find_by(id: params[:after_id]) + + Admins::DragCooperativeService.call(move, after) + render_ok + rescue Admins::DragCooperativeService::Error => e + render_error(e.message) + end + + def replace_image_url + current_coo.update!(url_states: Util::FileManage.disk_file_url('CooImg', current_coo.id)) + render_ok + end + + private + + def current_coo + @_current_coo ||= CooImg.find(params[:id]) + end + + def create_params + params.require(:coo_img).permit(:img_type, :src_states) + end + + def convert_file! + max_size = 10 * 1024 * 1024 # 10M + file = params.dig('coo_img', 'image') + if file.class == ActionDispatch::Http::UploadedFile + @file = file + render_error('请上传文件') if @file.size.zero? + render_error('文件大小超过限制') if @file.size > max_size + else + file = file.to_s.strip + return render_error('请上传正确的图片') if file.blank? + @file = Util.convert_base64_image(file, max_size: max_size) + end + rescue Base64ImageConverter::Error => ex + render_error(ex.message) + end +end \ No newline at end of file diff --git a/app/controllers/admins/department_applies_controller.rb b/app/controllers/admins/department_applies_controller.rb index 6c26e67af..458721e34 100644 --- a/app/controllers/admins/department_applies_controller.rb +++ b/app/controllers/admins/department_applies_controller.rb @@ -1,6 +1,7 @@ class Admins::DepartmentAppliesController < Admins::BaseController - before_action :get_apply,only:[:agree,:edit,:update,:destroy] + before_action :get_apply,only:[:agree,:destroy] + def index params[:status] ||= 0 params[:sort_by] = params[:sort_by].presence || 'created_at' @@ -19,46 +20,80 @@ class Admins::DepartmentAppliesController < Admins::BaseController end end - def update - depart_name = params[:name] + def merge + apply_id = params[:origin_department_id] + apply_add =ApplyAddDepartment.find(apply_id) + origin_id = apply_add&.department_id + new_id = params[:department_id] + + return render_error('请选择其它部门') if origin_id.to_s == new_id.to_s + + origin_department = apply_add&.department + to_department = Department.find(new_id) + + return render_error('部门所属单位不相同') if origin_department&.school_id != to_department&.school_id + ActiveRecord::Base.transaction do - @depart_apply.update_attribute("name",depart_name) - @depart_apply&.department&.update_attribute("name",depart_name) - extra = depart_name + "(#{@depart_apply&.department&.school&.try(:name)})" + applied_message = AppliedMessage.where(applied_id: origin_id, applied_type: "ApplyAddDepartment") + + applied_message.update_all(:status => 4) + apply_add.update_attribute(:status, 2) + apply_add.tidings.update_all(:status => 1) + + extra = to_department&.name + "(#{apply_add&.department&.school&.try(:name)})" tiding_params = { - user_id: @depart_apply.user_id, + user_id: apply_add.user_id, trigger_user_id: 0, - container_id: @depart_apply.id, + container_id: apply_add.id, container_type: 'ApplyAddDepartment', - belong_container_id: @depart_apply.department.school_id, + belong_container_id: apply_add&.department&.school_id, belong_container_type: "School", tiding_type: "System", status: 3, extra: extra } Tiding.create(tiding_params) - render_success_js + + origin_department.apply_add_departments.delete_all + + origin_department.user_extensions.update_all(department_id: new_id) + + if to_department.identifier.blank? && origin_department.identifier.present? + to_department.update!(identifier: origin_department.identifier) + end + + origin_department.destroy! + apply_add.destroy! end + render_ok end def destroy ActiveRecord::Base.transaction do @depart_apply.update_attribute("status",3) @depart_apply&.applied_messages&.update_all(status:3) + + if params[:tip] == 'unapplied' #未审批时候删除 + user_extens = UserExtension.where(department_id: @depart_apply.department_id) + user_extens.update_all(department_id:nil) + User.where(id: user_extens.pluck(:user_id)).update_all(profile_completed:false) + + tiding_params = { + user_id: @depart_apply.user_id, + trigger_user_id: 0, + container_id: @depart_apply.id, + container_type: 'ApplyAddDepartment', + belong_container_id: @depart_apply&.department&.school_id, + belong_container_type: "School", + tiding_type: "System", + status: 2, + extra: params[:reason] + } + Tiding.create(tiding_params) + end + @depart_apply&.department&.destroy - @depart_apply&.user&.user_extension&.update_attribute("department_id", nil) - tiding_params = { - user_id: @depart_apply.user_id, - trigger_user_id: 0, - container_id: @depart_apply.id, - container_type: 'ApplyAddDepartment', - belong_container_id: @depart_apply.department.school_id, - belong_container_type: "School", - tiding_type: "System", - status: 2, - extra: params[:reason] - } - Tiding.create(tiding_params) + @depart_apply.destroy render_success_js end end diff --git a/app/controllers/admins/ec_templates_controller.rb b/app/controllers/admins/ec_templates_controller.rb new file mode 100644 index 000000000..39216b014 --- /dev/null +++ b/app/controllers/admins/ec_templates_controller.rb @@ -0,0 +1,41 @@ +class Admins::EcTemplatesController < Admins::BaseController + + def index + @params_page = params[:page] || 1 + templates = EcTemplate.where(nil).includes(:attachments).order("updated_at desc") + @templates = paginate templates + end + + def create_template + ActiveRecord::Base.transaction do + if params[:template_id] == "-1" + ec_template = EcTemplate.new(name: params[:name]) + ec_template.save + else + ec_template = EcTemplate.find_by(id: params[:template_id]) + end + + if params[:attachment_id] != "-1" + attachment_id = params[:attachment_id] + attachment_tem = Attachment.find_by(id: attachment_id) + + unless attachment_tem.container_id.present? && attachment_tem.container_id == ec_template&.id + attachment_tem.update_attributes(container_id: ec_template&.id, container_type: "EcTemplate") + end + end + + @params_page = params[:page] || 1 + templates = EcTemplate.where(nil).includes(:attachments).order("updated_at desc") + @templates = paginate templates + end + end + + def destroy + ActiveRecord::Base.transaction do + template = EcTemplate.find_by(id: params[:id]) + template.destroy + render_success_js + end + end + +end diff --git a/app/controllers/admins/files_controller.rb b/app/controllers/admins/files_controller.rb index 3c799ceba..b269f8e27 100644 --- a/app/controllers/admins/files_controller.rb +++ b/app/controllers/admins/files_controller.rb @@ -6,7 +6,7 @@ class Admins::FilesController < Admins::BaseController Util.write_file(@file, file_path) - render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url) + render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url + "?t=#{Random.rand}") rescue StandardError => ex logger_error(ex) render_error('上传失败') @@ -33,22 +33,14 @@ class Admins::FilesController < Admins::BaseController @_file_path ||= begin case params[:source_type].to_s when 'Shixun' then - disk_filename('Shixun', params[:source_id]) + Util::FileManage.disk_filename('Shixun', params[:source_id]) else - disk_filename(params[:source_type].to_s, params[:source_id].to_s) + Util::FileManage.disk_filename(params[:source_type].to_s, params[:source_id].to_s) end end end - def disk_filename(type, id) - File.join(storage_path, type.to_s, id.to_s) - end - - def storage_path - @_storage_path ||= File.join(Rails.root, 'public', 'images', 'avatars') - end - def file_url - File.join('/images/avatars/', params[:source_type].to_s, params[:source_id].to_s) + Util::FileManage.disk_file_url(params[:source_type].to_s, params[:source_id].to_s) end end \ No newline at end of file diff --git a/app/controllers/admins/graduation_standards_controller.rb b/app/controllers/admins/graduation_standards_controller.rb new file mode 100644 index 000000000..7fbd8924f --- /dev/null +++ b/app/controllers/admins/graduation_standards_controller.rb @@ -0,0 +1,33 @@ +class Admins::GraduationStandardsController < Admins::BaseController + + def index + standards = EcGraduationStandard.all.order("updated_at desc") + @params_page = params[:page] || 1 + @standards = paginate standards + end + + def create_standard + ActiveRecord::Base.transaction do + if params[:graduation_id] == "-1" + content = params[:content] + EcGraduationStandard.create(:content => content) + else + graduation = EcGraduationStandard.find_by(id: params[:graduation_id]) + graduation.update_attribute(:content, params[:content]) + end + + standards = EcGraduationStandard.all.order("updated_at desc") + @params_page = params[:page] || 1 + @standards = paginate standards + end + end + + def destroy + ActiveRecord::Base.transaction do + @graduation = EcGraduationStandard.find_by(id: params[:id]) + @graduation.destroy + render_success_js + end + end + +end \ No newline at end of file diff --git a/app/controllers/admins/help_centers_controller.rb b/app/controllers/admins/help_centers_controller.rb new file mode 100644 index 000000000..5e8fa5a94 --- /dev/null +++ b/app/controllers/admins/help_centers_controller.rb @@ -0,0 +1,18 @@ +class Admins::HelpCentersController < Admins::BaseController + def edit + current_doc + end + + def update + current_doc.update!(help_center: params[:help_center]) + + flash[:success] = '保存成功' + redirect_to edit_admins_help_center_path + end + + private + + def current_doc + @doc ||= Help.first || Help.create + end +end \ No newline at end of file diff --git a/app/controllers/admins/major_informations_controller.rb b/app/controllers/admins/major_informations_controller.rb new file mode 100644 index 000000000..931476c8c --- /dev/null +++ b/app/controllers/admins/major_informations_controller.rb @@ -0,0 +1,8 @@ +class Admins::MajorInformationsController < Admins::BaseController + + def index + disciplines = EcDiscipline.includes(ec_discipline_firsts: {ec_majors: :schools}).order("ec_disciplines.code asc") + @disciplines = paginate disciplines + end + +end \ No newline at end of file diff --git a/app/controllers/admins/unit_applies_controller.rb b/app/controllers/admins/unit_applies_controller.rb new file mode 100644 index 000000000..deb231f16 --- /dev/null +++ b/app/controllers/admins/unit_applies_controller.rb @@ -0,0 +1,122 @@ +class Admins::UnitAppliesController < Admins::BaseController + before_action :get_apply,only: [:agree,:destroy,:edit,:update] + + def index + params[:sort_by] ||= 'created_at' + params[:sort_direction] ||= 'desc' + unit_applies = Admins::UnitApplyQuery.call(params) + @unit_applies = paginate unit_applies.preload(:school, :user) + end + + def agree + ActiveRecord::Base.transaction do + begin + @unit_apply.update_attribute("status",1) + @unit_apply&.applied_messages&.update_all(status:1) + @unit_apply&.school&.update_attribute("province",@unit_apply.province) + + # #申请信息的创建 + apply_message_params = { + user_id: @unit_apply&.user_id, + status: 1, + viewed: 0, + applied_id: @unit_apply.school_id, + applied_type: "ApplyAddSchools", + name: @unit_apply.name, + } + AppliedMessage.new(apply_message_params).save(validate: false) + + Tiding.where(user_id: 1, trigger_user_id: @unit_apply.user_id, container_id: @unit_apply.id, + container_type: 'ApplyAddSchools', status: 0, tiding_type: "Apply").update_all(status: 1) + #消息的创建 + tiding_params = { + user_id: @unit_apply.user_id, + trigger_user_id: 0, + container_id: @unit_apply.id, + container_type: 'ApplyAddSchools', + belong_container_id: @unit_apply.school_id, + belong_container_type: "School", + tiding_type: "System", + status: 1 + } + Tiding.create(tiding_params) + render_success_js + rescue Exception => e + Rails.logger.info("############_________________#########{e}") + end + end + end + + def destroy + Admins::DeleteUnitApplyService.call(@unit_apply, params) + render_success_js + end + + def edit + @all_schools = School.where.not(id: @unit_apply.school_id).pluck("name","id") + + end + + def update + school = School.find_by(id: params[:school_id]) + ActiveRecord::Base.transaction do + @unit_apply&.applied_messages&.update_all(status:4) + Tiding.where(user_id: 1, trigger_user_id: @unit_apply.user_id, container_id: @unit_apply.id, + container_type: 'ApplyAddSchools', status: 0, tiding_type: "Apply").update_all(status: 1) + + #消息的创建 + tiding_params = { + user_id: @unit_apply.user_id, + trigger_user_id: 0, + container_id: @unit_apply.id, + container_type: 'ApplyAddSchools', + belong_container_id: params[:school_id], + belong_container_type: "School", + tiding_type: "System", + status: 3, + extra: school.try(:name).to_s + } + Tiding.create(tiding_params) + + UserExtension.where(school_id: @unit_apply.school_id).update_all(school_id: params[:school_id].to_i) + ApplyAddDepartment.where(:school_id => @unit_apply.school_id).update_all(school_id: params[:school_id].to_i) + + # 判断重复 + before_apply_departments = Department.where(school_id: @unit_apply.school_id) + before_apply_departments.each do |department| + after_dep = Department.where(school_id: params[:school_id].to_i, name: department.name)&.first + if after_dep.present? + UserExtension.where(school_id: @unit_apply.school_id, department_id: department.id).update_all(department_id: after_dep.id) + department.destroy + department.apply_add_departments.destroy_all + else + department.apply_add_departments.update_all(school_id: school.id) + department.update_attribute(:school_id, school.id) + end + end + + @unit_apply&.school&.destroy + apply_params = { + status: 2, + name: school&.name.to_s, + school_id: params[:school_id], + province: params[:province], + city: params[:city], + address: params[:address] + } + @unit_apply.update_attributes(apply_params) + # render_success_js + end + end + + private + + def get_apply + @unit_apply = ApplyAddSchool.find_by(id:params[:id]) + end + + def disk_auth_filename(source_type, source_id, type) + File.join(storage_path, "#{source_type}", "#{source_id}#{type}") + end +end + diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9f2813940..e338c1c63 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -45,6 +45,13 @@ class ApplicationController < ActionController::Base uid_logger("###############user_course_identity:#{@user_course_identity}") end + # 题库的访问权限 + def bank_visit_auth + tip_exception(-2,"未通过职业认证") if current_user.is_teacher? && !current_user.certification_teacher? && !current_user.admin? && @bank.user_id != current_user.id && @bank.is_public + tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || + (current_user.certification_teacher? && @bank.is_public) + end + # 判断用户的邮箱或者手机是否可用 # params[:type] 1: 注册;2:忘记密码 @@ -246,7 +253,7 @@ class ApplicationController < ActionController::Base # 测试版前端需求 logger.info("subdomain:#{request.subdomain}") - if request.subdomain == "pre-newweb" + if request.subdomain == "test-newweb" if params[:debug] == 'teacher' #todo 为了测试,记得讲debug删除 User.current = User.find 81403 elsif params[:debug] == 'student' diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb index 8cb68b1d4..c21a493e0 100644 --- a/app/controllers/challenges_controller.rb +++ b/app/controllers/challenges_controller.rb @@ -191,21 +191,28 @@ class ChallengesController < ApplicationController sets_input = test_set.map(&:input) sets_open = test_set.map(&:is_public) set_score = test_set.map(&:score) + set_match_rule = test_set.map(&:match_rule) params_hidden = params[:test_set].map{|set| set[:hidden].to_i == 0} params_output = params[:test_set].map{|set| set[:output] } params_input = params[:test_set].map{|set| set[:input] } params_score = params[:test_set].map{|set| set[:score]} + params_test_set = params[:test_set].map{|set| set[:match_rule]} # 测试集变化则需要更新(输入、 输出、 是否隐藏) - if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || set_score != params_score + if sets_output != params_output || sets_open != params_hidden || sets_input != params_input || + set_score != params_score || params_test_set != set_match_rule test_set.delete_all unless test_set.blank? - params[:test_set].each_with_index do |set, index| - TestSet.create(:challenge_id => @challenge.id, - :input => "#{set[:input]}", - :output => "#{set[:output]}", - :is_public => params_hidden[index], - :score => set[:score], - :position => (index + 1)) - end + params[:test_set].each_with_index do |set, index| + # last: 末尾匹配, full: 全完匹配 + logger.info("set: #{set}; match_rule : #{set[:match_rule]}") + match_rule = set[:match_rule] == 'last' ? 'last' : 'full' + TestSet.create(:challenge_id => @challenge.id, + :input => "#{set[:input]}", + :output => "#{set[:output]}", + :is_public => params_hidden[index], + :score => set[:score], + :match_rule => "#{match_rule}", + :position => (index + 1)) + end @challenge.update_column(:modify_time, Time.now) # 测试集的 @shixun.myshixuns.update_all(:system_tip => 0) diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index eeb4671a4..9242b87ac 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -21,7 +21,7 @@ module GitHelper content = Base64.decode64(content) cd = CharDet.detect(content) Rails.logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" - + # 字符编码问题,GB18030编码识别率不行 decode_content = if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) diff --git a/app/controllers/course_stages_controller.rb b/app/controllers/course_stages_controller.rb new file mode 100644 index 000000000..92e44a336 --- /dev/null +++ b/app/controllers/course_stages_controller.rb @@ -0,0 +1,105 @@ +class CourseStagesController < ApplicationController + before_action :require_login + before_action :find_course, only: [:create] + before_action :find_course_stage, only: [:update, :destroy, :edit, :up_position, :down_position] + before_action :user_course_identity, :teacher_allowed + + def create + ActiveRecord::Base.transaction do + begin + @stage = CourseStage.new(stage_params) + @stage.course_id = @course.id + @stage.position = @course.course_stages.count + 1 + @stage.save! + unless params[:shixun_id].blank? + shixuns = Shixun.where(id: params[:shixun_id]).order("field(id, #{params[:shixun_id].join(",")})") + shixuns.each do |shixun| + CourseStageShixun.create!(course_stage_id: @stage.id, course_id: @course.id, shixun_id: shixun.id, position: @stage.course_stage_shixuns.count + 1) + end + end + normal_status("创建成功") + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def edit + + end + + def update + ActiveRecord::Base.transaction do + begin + @stage.update_attributes!(stage_params) + @stage.course_stage_shixuns.destroy_all + unless params[:shixun_id].blank? + params[:shixun_id].each do |shixun_id| + shixun = Shixun.where(id: shixun_id).first + @stage.course_stage_shixuns.create!(course_id: @course.id, shixun_id: shixun.id, position: @stage.course_stage_shixuns.count + 1) if shixun.present? + end + end + normal_status("更新成功") + rescue Exception => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback + end + end + end + + def destroy + ActiveRecord::Base.transaction do + @course.course_stages.where("position > ?", @stage.position).update_all("position = position - 1") + @stage.destroy! + normal_status("删除成功") + end + end + + def up_position + ActiveRecord::Base.transaction do + begin + position = @stage.position + tip_exception("第一章不能向上移动") if @stage.position == 1 + pre_stage = @course.course_stages.where(position: position - 1).first + pre_stage.update_attributes(position: position) + @stage.update_attributes(position: position - 1) + normal_status("更新成功") + rescue Exception => e + uid_logger("stage up failed: #{e.message}") + raise ActiveRecord::Rollback + end + end + end + + def down_position + ActiveRecord::Base.transaction do + begin + position = @stage.position + rails "最后一章不能向下移动" if @stage.position == @course.course_stages.count + next_stage = @course.course_stages.where(position: position + 1).first + next_stage.update_attributes(position: position) + @stage.update_attributes(position: position + 1) + normal_status("更新成功") + rescue Exception => e + uid_logger("stage up failed: #{e.message}") + raise ActiveRecord::Rollback + end + end + end + + private + + def find_course_stage + @stage = CourseStage.find_by!(id: params[:id]) + @course = @stage.course + end + + def stage_params + tip_exception("章节名称不能为空") if params[:name].blank? + params.permit(:name, :description) + end + +end diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index 10d733a94..0dc8829da 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -33,10 +33,11 @@ class CoursesController < ApplicationController before_action :teacher_allowed, only: [:update, :destroy, :settings, :search_teacher_candidate, :transfer_to_course_group, :delete_from_course, :export_member_scores_excel, :search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, - :add_teacher, :export_couser_info, :export_member_act_score] + :add_teacher, :export_couser_info, :export_member_act_score, + :update_informs, :new_informs, :delete_informs] before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin, - :set_course_group, :create_group_by_importing_file, :update_informs, :new_informs, - :update_task_position, :tasks_list, :delete_informs] + :set_course_group, :create_group_by_importing_file, + :update_task_position, :tasks_list] before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group, :change_course_teacher, :course_group_list, :teacher_application_review, :apply_teachers, :delete_course_teacher] @@ -166,6 +167,8 @@ class CoursesController < ApplicationController end Inform.create(container: @course, description: @subject.learning_notes, name: "学习须知") + + @course.create_stages @course.subject end course_module_types = params[:course_module_types] @@ -265,9 +268,9 @@ class CoursesController < ApplicationController def online_learning @subject = @course.subject - @stages = @subject&.stages + @stages = @course.course_stages @user = current_user - @start_learning = @user_course_identity == Course::STUDENT && @subject&.learning?(current_user.id) + @start_learning = @user_course_identity == Course::STUDENT && @course.learning?(current_user.id) end def search_course_list @@ -303,7 +306,7 @@ class CoursesController < ApplicationController def destroy if @course.is_delete == 0 @course.delete! - Tiding.create!(user_id: @course.tea_id, trigger_user_id: 1, container_id: @course.id, + Tiding.create!(user_id: @course.tea_id, trigger_user_id: 0, container_id: @course.id, container_type: 'Course', tiding_type: 'Delete', extra: @course.name) normal_status(0, "成功") else @@ -423,7 +426,7 @@ class CoursesController < ApplicationController active_student_exist = CourseMember.where(user_id: user[:user_id], role: 4, course_id: @course.id, is_active: 1).any? is_active = active_student_exist ? 0 : 1 user_id = User.find(user[:user_id]).id - existing_teacher = CourseMember.find_by(course_id: @course.id, user_id: user_id, role: role) + existing_teacher = CourseMember.find_by(course_id: @course.id, user_id: user_id, role: %i[CREATOR PROFESSOR ASSISTANT_PROFESSOR]) if existing_teacher.blank? teacher_ids << user_id member = CourseMember.create(course_id: @course.id, graduation_group_id: @graduation_group_id, user_id: user_id, role: role, is_active: is_active) @@ -707,6 +710,7 @@ class CoursesController < ApplicationController def students search = params[:search].present? ? params[:search].strip : nil order = params[:order].present? ? params[:order].to_i : 0 + sort = params[:sort].present? ? params[:sort] : "desc" course_group_id = params[:course_group_id].present? ? params[:course_group_id].to_i : nil @students = CourseMember.students(@course) @@ -718,12 +722,12 @@ class CoursesController < ApplicationController if order == 1 # REDO:Extension - @students = @students.includes(user: :user_extension).order("user_extensions.student_id, users.login") + @students = @students.includes(user: :user_extension).order("user_extensions.student_id #{sort}, users.login #{sort}") elsif order == 2 - @students = @students.includes(:course_group).order("course_groups.position, users.login") + @students = @students.includes(:course_group).order("course_groups.position #{sort}, users.login #{sort}") else # REDO:Extension - @students = @students.includes(user: :user_extension).order("user_extensions.student_id, users.login") + @students = @students.includes(user: :user_extension).order("user_extensions.student_id #{sort}, users.login #{sort}") end if course_group_id.present? @@ -808,43 +812,37 @@ class CoursesController < ApplicationController # 搜索添加学生 def add_students_by_search + student_ids = [] ActiveRecord::Base.transaction do - begin - user_ids = params[:user_ids] - course_group_id = params[:course_group_id].to_i - if course_group_id != 0 - course_group = CourseGroup.find(course_group_id) - course_group_id = course_group.id - end + user_ids = params[:user_ids] + course_group_id = params[:course_group_id].to_i + if course_group_id != 0 + course_group = CourseGroup.find(course_group_id) + course_group_id = course_group.id + end - student_ids = [] - user_ids.each do |user_id| - existing_course_member = @course.course_members.find_by(user_id: user_id.to_i) - new_student = CourseMember.new(user_id: user_id.to_i, course_id: @course.id, course_group_id: course_group_id, role: 4) + user_ids.each do |user_id| + existing_course_member = @course.course_members.find_by(user_id: user_id.to_i) + new_student = CourseMember.new(user_id: user_id.to_i, course_id: @course.id, course_group_id: course_group_id, role: 4) - if existing_course_member.present? - if existing_course_member.STUDENT? - existing_course_member.update_attributes(course_group_id: course_group_id) - else - new_student.is_active = 0 if existing_course_member.is_active - new_student.save! - student_ids << user_id - end + if existing_course_member.present? + if existing_course_member.STUDENT? + existing_course_member.update_attributes(course_group_id: course_group_id) else + new_student.is_active = 0 if existing_course_member.is_active new_student.save! student_ids << user_id end + else + new_student.save! + student_ids << user_id end - - CourseAddStudentCreateWorksJob.perform_later(@course.id, student_ids) if student_ids.present? - TeacherInviteJoinCourseNotifyJob.perform_later(current_user.id, @course.id, 10, student_ids) if student_ids.present? - normal_status(0, "添加成功") - rescue => e - uid_logger(e.message) - tip_exception("添加失败") - raise ActiveRecord::Rollback end end + + CourseAddStudentCreateWorksJob.perform_later(@course.id, student_ids) if student_ids.present? + TeacherInviteJoinCourseNotifyJob.perform_later(current_user.id, @course.id, 10, student_ids) if student_ids.present? + normal_status(0, "添加成功") end # 获取历史课堂,即用户管理的所有课堂以及课堂下的分班(去除当前课堂) diff --git a/app/controllers/exercise_banks_controller.rb b/app/controllers/exercise_banks_controller.rb index dafaf131e..9a35bfcdb 100644 --- a/app/controllers/exercise_banks_controller.rb +++ b/app/controllers/exercise_banks_controller.rb @@ -1,7 +1,7 @@ #encoding: UTF-8 class ExerciseBanksController < ApplicationController before_action :require_login - before_action :find_bank, except: [:choose_shixun] + before_action :find_bank, :bank_visit_auth, except: [:choose_shixun] before_action :bank_admin, only: [:update] before_action :commit_shixun_present, only: [:commit_shixun] @@ -64,8 +64,6 @@ class ExerciseBanksController < ApplicationController def find_bank @bank = ExerciseBank.find_by!(id: params[:id]) - tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || - (current_user.certification_teacher? && @bank.is_public) end def bank_admin @@ -74,7 +72,7 @@ class ExerciseBanksController < ApplicationController #判断实训是否已选择 def commit_shixun_present - question_shixun_ids = @exercise.exercise_bank_questions.pluck(:shixun_id).reject(&:blank?) + question_shixun_ids = @bank.exercise_bank_questions.pluck(:shixun_id).reject(&:blank?) shixun_id = params[:shixun_id] @shixun = Shixun.find_by(id: shixun_id) if shixun_id.present? && question_shixun_ids.include?(shixun_id) @@ -85,45 +83,47 @@ class ExerciseBanksController < ApplicationController end def get_exercise_question_count - @exercise_ques_count = @exercise_questions.size # 全部的题目数 - @exercise_ques_scores = @exercise_questions.pluck(:question_score).sum + exercise_questions = @bank.exercise_bank_questions + @exercise_ques_count = exercise_questions.size # 全部的题目数 + @exercise_ques_scores = exercise_questions.pluck(:question_score).sum #单选题的数量及分数 - exercise_single_ques = @exercise_questions.find_by_custom("question_type", Exercise::SINGLE) + exercise_single_ques = exercise_questions.find_by_custom("question_type", Exercise::SINGLE) @exercise_single_ques_count = exercise_single_ques.size @exercise_single_ques_scores = exercise_single_ques.pluck(:question_score).sum #多选题的数量及分数 - exercise_double_ques = @exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE) + exercise_double_ques = exercise_questions.find_by_custom("question_type", Exercise::MULTIPLE) @exercise_double_ques_count = exercise_double_ques.size @exercise_double_ques_scores = exercise_double_ques.pluck(:question_score).sum # 判断题数量及分数 - exercise_ques_judge = @exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT) + exercise_ques_judge = exercise_questions.find_by_custom("question_type", Exercise::JUDGMENT) @exercise_ques_judge_count = exercise_ques_judge.size @exercise_ques_judge_scores = exercise_ques_judge.pluck(:question_score).sum #填空题数量及分数 - exercise_ques_null = @exercise_questions.find_by_custom("question_type", Exercise::COMPLETION) + exercise_ques_null = exercise_questions.find_by_custom("question_type", Exercise::COMPLETION) @exercise_ques_null_count = exercise_ques_null.size @exercise_ques_null_scores = exercise_ques_null.pluck(:question_score).sum #简答题数量及分数 - exercise_ques_main = @exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE) + exercise_ques_main = exercise_questions.find_by_custom("question_type", Exercise::SUBJECTIVE) @exercise_ques_main_count = exercise_ques_main.size @exercise_ques_main_scores = exercise_ques_main.pluck(:question_score).sum #实训题数量及分数 - exercise_ques_shixun = @exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL) + exercise_ques_shixun = exercise_questions.find_by_custom("question_type", Exercise::PRACTICAL) @exercise_ques_shixun_count = exercise_ques_shixun.size @exercise_ques_shixun_scores = exercise_ques_shixun.pluck(:question_score).sum end def get_poll_question_count - @poll_questions_count = @exercise_questions&.size # 全部的题目数 - @poll_question_singles = @exercise_questions.find_by_custom("question_type", 1).size # 单选题 - @poll_question_doubles = @exercise_questions.find_by_custom("question_type", 2).size # 多选题 - @poll_question_mains = @exercise_questions.find_by_custom("question_type", 3).size #主观题 + exercise_questions = @bank.exercise_bank_questions + @poll_questions_count = exercise_questions&.size # 全部的题目数 + @poll_question_singles = exercise_questions.find_by_custom("question_type", 1).size # 单选题 + @poll_question_doubles = exercise_questions.find_by_custom("question_type", 2).size # 多选题 + @poll_question_mains = exercise_questions.find_by_custom("question_type", 3).size #主观题 end end diff --git a/app/controllers/exercise_questions_controller.rb b/app/controllers/exercise_questions_controller.rb index 57116a9e5..bb28fff54 100644 --- a/app/controllers/exercise_questions_controller.rb +++ b/app/controllers/exercise_questions_controller.rb @@ -494,20 +494,88 @@ class ExerciseQuestionsController < ApplicationController def adjust_score ActiveRecord::Base.transaction do begin + ex_all_scores = @exercise.exercise_questions.pluck(:question_score).sum ex_obj_score = @exercise_current_user.objective_score #全部客观题得分 ex_subj_score = @exercise_current_user.subjective_score < 0.0 ? 0.0 : @exercise_current_user.subjective_score #全部主观题得分 ex_answers = @exercise_question.exercise_answers.search_answer_users("user_id",@user_id) #当前用户答案的得分 - if @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分, - ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 - each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 - new_obj_score = ex_obj_score - ex_answer_old + @c_score + if @exercise_question.question_type == Exercise::MULTIPLE + if ex_answers.present? #学生有回答时 取学生的答题得分,否则0分 + answer_choice_array = [] + ex_answers.each do |a| + if a.try(:exercise_choice).try(:choice_position).present? + answer_choice_array.push(a&.exercise_choice&.choice_position) #学生答案的位置 + end + end + user_answer_content = answer_choice_array.reject(&:blank?).sort + standard_answer = @exercise_question.exercise_standard_answers.pluck(:exercise_choice_id).sort + if standard_answer.size == 1 # 老数据需要判断学生答题是否正确, 正确取原题得分,否则是0分 + standard_answer = standard_answer.first.to_s.split("").map(&:to_i).sort + if user_answer_content == standard_answer + ex_answer_old = @exercise_question.question_score + else + ex_answer_old = 0 + end + else # 新多选题只需取第一条答题记录的得分 + ex_answer_old = ex_answers.first.score > 0 ? ex_answers.first.score : 0 + end + ex_answers.update_all(:score => @c_score) #所有的正确选项需重新更新 + else + answer_option = { + :user_id => @user_id, + :exercise_question_id => @exercise_question.id, + :score => @c_score, + :answer_text => "" + } + ExerciseAnswer.create(answer_option) + ex_answer_old = 0 + end + if ex_obj_score <= 0.0 + new_obj_score = @c_score + else + new_obj_score = ex_obj_score - ex_answer_old + @c_score + end + total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end + ex_scores = { + :objective_score => new_obj_score, + :score => total_scores + } + @exercise_current_user.update_attributes(ex_scores) + + elsif @exercise_question.question_type == Exercise::COMPLETION #当为填空题,更新问题的总分, + + if ex_answers.exists? + ex_answer_old = ex_answers.score_reviewed.pluck(:score).sum #每一关的得分总和 + each_right_score = (@c_score / ex_answers.count.to_f) #调分后,平均每关的分数 + new_obj_score = ex_obj_score - ex_answer_old + @c_score + ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 + else #如果学生未答,则创建新的答题记录 + answer_option = { + :user_id => @user_id, + :exercise_question_id => @exercise_question.id, + :score => @c_score, + :answer_text => "" + } + ExerciseAnswer.create(answer_option) + new_obj_score = ex_obj_score + @c_score + end + + total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :objective_score => new_obj_score, :score => total_scores } @exercise_current_user.update_attributes(ex_scores) - ex_answers.update_all(:score => each_right_score) #所有的正确选项需重新更新 elsif @exercise_question.question_type == Exercise::SUBJECTIVE #当为主观题时 if ex_answers.exists? ex_answers_old_score = ex_answers.first.score > 0.0 ? ex_answers.first.score : 0.0 #原分数小于0,取0 @@ -524,6 +592,11 @@ class ExerciseQuestionsController < ApplicationController new_sub_score = ex_subj_score + @c_score end total_scores = ex_obj_score + new_sub_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :subjective_score => new_sub_score, :score => total_scores @@ -549,6 +622,11 @@ class ExerciseQuestionsController < ApplicationController new_obj_score = @c_score end total_scores = new_obj_score + ex_subj_score + if total_scores < 0.0 + total_scores = 0.0 + elsif total_scores > ex_all_scores + total_scores = ex_all_scores + end ex_scores = { :objective_score => new_obj_score, :score => total_scores @@ -556,30 +634,33 @@ class ExerciseQuestionsController < ApplicationController @exercise_current_user.update_attributes(ex_scores) end comments = params[:comment] - question_comment = @exercise_question.exercise_answer_comments.first + question_comment = @exercise_question.exercise_answer_comments&.first + if question_comment.present? comment_option = { - :comment => comments.present? ? comments : question_comment.comment, + :comment => comments, :score => @c_score, - :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil, + :user_id => current_user.id } question_comment.update_attributes(comment_option) @exercise_comments = question_comment else + ex_answer_comment_id = @exercise_question.exercise_answers.find_by(user_id: @user_id).try(:id) comment_option = { :user_id => current_user.id, :comment => comments, :score => @c_score, :exercise_question_id => @exercise_question.id, :exercise_shixun_answer_id => @shixun_a_id.present? ? @shixun_a_id : nil, - :exercise_answer_id => ex_answers.present? ? ex_answers.first.id : nil + :exercise_answer_id => ex_answer_comment_id } @exercise_comments = ExerciseAnswerComment.new(comment_option) @exercise_comments.save end rescue Exception => e uid_logger_error(e.message) - tip_exception("没有权限") + tip_exception(e.message) raise ActiveRecord::Rollback end end @@ -703,8 +784,8 @@ class ExerciseQuestionsController < ApplicationController normal_status(-1,"用户不存在!") elsif @c_score.blank? normal_status(-1,"分数不能为空!") - elsif @exercise_question.question_type <= Exercise::JUDGMENT - normal_status(-1,"选择题/判断题不能调分!") + elsif @exercise_question.question_type == Exercise::SINGLE || @exercise_question.question_type == Exercise::JUDGMENT + normal_status(-1,"单选题/判断题不能调分!") elsif params[:comment].present? && params[:comment].length > 100 normal_status(-1,"评语不能超过100个字符!") else diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index 2807a0215..b9da12ab0 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -59,24 +59,9 @@ class GamesController < ApplicationController record_onsume_time: record_onsume_time, prev_game: prev_game, next_game: next_game, praise_count: praise_count, user_praise: user_praise, time_limit: time_limit, tomcat_url: edu_setting('cloud_tomcat_php'), is_teacher: is_teacher, - myshixun_manager: myshixun_manager} + myshixun_manager: myshixun_manager, git_url: (@shixun.vnc ? repo_url(@myshixun.repo_path) : "")} if @shixun.vnc - begin - shixun_tomcat = edu_setting('cloud_bridge') - service_host = edu_setting('vnc_url') - uri = "#{shixun_tomcat}/bridge/vnc/getvnc" - params = {tpiID: @myshixun.id, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(@shixun))}"} - res = uri_post uri, params - if res && res['code'].to_i != 0 - raise("实训云平台繁忙(繁忙等级:99)") - end - # 无域名版本 - #@vnc_url = "http://#{service_host}:#{res['port']}/vnc_lite.html?password=headless" - # 有域名版本 - @vnc_url = "https://#{res['port']}.#{service_host}/vnc_lite.html?password=headless" - rescue Exception => e - Rails.logger.error(e.message) - end + get_vnc_link(@game) end # 区分选择题和编程题,st:0编程题; @@ -103,6 +88,21 @@ class GamesController < ApplicationController end end + def reset_vnc_link + begin + # 删除vnc的pod + delete_vnc(@game) + # 重新连接 + get_vnc_link(@game) + + render :json => {status: 1, message: "重置VNC成功", data: {vnc_url: @vnc_url, vnc_evaluate: @vnc_evaluate}} + rescue Exception => e + logger.error("############'#{e.message}'") + tip_exception("实训云平台繁忙") + end + + end + # 查看效果 # todo : 这块代码有很大的改进空间 # todo : 中文排序问题 @@ -530,18 +530,21 @@ class GamesController < ApplicationController game_challenge.test_sets.each do |test_set| input = test_set.input.nil? ? "" : test_set.input.gsub("\r\n", "\n") output = test_set.output.nil? ? "" : test_set.output.gsub("\r\n", "\n") - test_cases = {:input => input, :output => output} + test_cases = {:input => input, :output => output, :matchRule => test_set.match_rule} testSet << test_cases end - testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank? + logger.info("##############testSet: #{testSet}") + testCases = Base64.urlsafe_encode64(testSet.to_json) unless testSet.blank? + # 评测类型: 0,1,2 用于webssh的评测, 3用于vnc + podType = @shixun.vnc_evaluate ? 3 : @shixun.webssh # 注意:这个地方的参数写的时候不能换行 content_modified = params[:content_modified] # 决定文件内容是否有修改,有修改如果中间层pull没有更新,则轮询等待更新 br_params = {:tpiID => "#{@myshixun.id}", :tpiGitURL => "#{gitUrl}", :buildID => "#{@game.id}", :instanceChallenge => "#{step}", :testCases => "#{testCases}", :resubmit => "#{resubmit}", - :times => params[:first].to_i, :podType => @shixun.webssh, :content_modified => content_modified, + :times => params[:first].to_i, :podType => podType, :content_modified => content_modified, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(@shixun))}", :persistenceName => @shixun.identifier, :tpmScript => "#{tpmScript}", :sec_key => sec_key, :timeLimit => game_challenge.exec_time, :isPublished => (@shixun.status < 2 ? 0 : 1) } @@ -552,6 +555,15 @@ class GamesController < ApplicationController # needPortMapping: web类型需要pod端口映射 br_params[:needPortMapping] = 8080 if @myshixun.mirror_name.include?("Web") + # 私密仓库的设置 + secret_rep = @shixun.shixun_secret_repository + logger.info("############secret_rep: #{secret_rep}") + if secret_rep&.repo_name + secretGitUrl = repo_url secret_rep.repo_path + br_params.merge!({secretGitUrl: Base64.urlsafe_encode64(secretGitUrl), secretDir: secret_rep.secret_dir_path}) + logger.info("#######br_params:#{br_params}") + end + # 中间层交互 uri = "#{shixun_tomcat}/bridge/game/gameEvaluate" res = interface_post uri, br_params, 502, "gameEvaluate failed" @@ -861,7 +873,7 @@ class GamesController < ApplicationController choose.challenge_questions.each do |question| position = question.position option_name = question.option_name - challenge_question << {:positon => position, :option_name => option_name} + challenge_question <<{:positon => position, :option_name => option_name} end # actual_output为空表示暂时没有评测答题,不允许查看 actual_output = output.try(:actual_output).try(:strip) @@ -922,4 +934,47 @@ class GamesController < ApplicationController game.myshixun.update_column(:updated_at, Time.now) end + # vnc连接 + def get_vnc_link game + begin + shixun = game.myshixun.shixun + shixun_tomcat = edu_setting('cloud_bridge') + service_host = edu_setting('vnc_url') + uri = "#{shixun_tomcat}/bridge/vnc/getvnc" + params = {tpiID: game.myshixun.id, :containers => "#{Base64.urlsafe_encode64(shixun_container_limit(shixun))}"} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:99)") + end + @vnc_url = + if request.subdomain == "pre-newweb" || request.subdomain == "test-newweb" + # 无域名版本 + "http://#{service_host}:#{res['port']}/vnc_lite.html?password=headless" + else + # 有域名版本 + "https://#{res['port']}.#{service_host}/vnc_lite.html?password=headless" + end + @vnc_evaluate = shixun.vnc_evaluate + rescue Exception => e + Rails.logger.error(e.message) + end + end + + # 删除pod + def delete_vnc game + myshixun_id = game.myshixun_id + digest = game.identifier + edu_setting('bridge_secret_key') + digest_key = Digest::SHA1.hexdigest("#{digest}") + begin + shixun_tomcat = edu_setting('cloud_bridge') + uri = "#{shixun_tomcat}/bridge/vnc/delete" + Rails.logger.info("#{current_user} => cloese_vnc digest is #{digest}") + params = {:tpiID => myshixun_id, :digestKey => digest_key, :identifier => game.identifier} + res = uri_post uri, params + if res && res['code'].to_i != 0 + raise("实训云平台繁忙(繁忙等级:110)") + end + end + end + end diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb index 49a4ead78..fe8bd660c 100644 --- a/app/controllers/graduation_tasks_controller.rb +++ b/app/controllers/graduation_tasks_controller.rb @@ -327,9 +327,9 @@ class GraduationTasksController < ApplicationController 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] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) - ActiveRecord::Base.transaction do + # ActiveRecord::Base.transaction do begin tasks = @course.graduation_tasks.where(id: params[:task_ids], status: 0). where("publish_time is null or publish_time > '#{Time.now}'") @@ -353,7 +353,7 @@ class GraduationTasksController < ApplicationController tip_exception(e.message) raise ActiveRecord::Rollback end - end + # end end def end_task @@ -404,7 +404,7 @@ class GraduationTasksController < ApplicationController 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 + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.publish_time = params[:publish_time] @task.end_time = params[:end_time] @@ -417,7 +417,7 @@ class GraduationTasksController < ApplicationController tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") 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 + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.end_time = params[:end_time] end @@ -429,7 +429,7 @@ class GraduationTasksController < ApplicationController tip_exception("补交结束时间不能为空") if params[:late_time].blank? tip_exception("补交结束时间不能早于截止时间") if params[:late_time] <= @task.end_time tip_exception("补交结束时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:late_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:late_time] > strf_time(@course.end_date.end_of_day) tip_exception("迟交扣分应为正整数") if params[:late_penalty] && params[:late_penalty].to_i < 0 @task.allow_late = true diff --git a/app/controllers/graduation_topics_controller.rb b/app/controllers/graduation_topics_controller.rb index 0242bff21..0e6135e8c 100644 --- a/app/controllers/graduation_topics_controller.rb +++ b/app/controllers/graduation_topics_controller.rb @@ -109,8 +109,8 @@ class GraduationTopicsController < ApplicationController @attachments = @graduation_topic.attachments left_banner_content = @course.course_modules.search_by_module_type("graduation") if left_banner_content.present? - @left_banner_id = left_banner_content.first.course_second_categories.first.id - @left_banner_name = left_banner_content.first.course_second_categories.first.name + @left_banner_id = left_banner_content.first.id + @left_banner_name = "毕设选题" end end diff --git a/app/controllers/gtopic_banks_controller.rb b/app/controllers/gtopic_banks_controller.rb index 291302bc2..f09a8554c 100644 --- a/app/controllers/gtopic_banks_controller.rb +++ b/app/controllers/gtopic_banks_controller.rb @@ -1,6 +1,6 @@ class GtopicBanksController < ApplicationController before_action :require_login - before_action :find_bank + before_action :find_bank, :bank_visit_auth before_action :bank_admin, only: [:edit, :update] def show @@ -23,8 +23,6 @@ class GtopicBanksController < ApplicationController def find_bank @bank = GtopicBank.find_by!(id: params[:id]) - tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || - (current_user.certification_teacher? && @bank.is_public) end def bank_admin diff --git a/app/controllers/helps_controller.rb b/app/controllers/helps_controller.rb new file mode 100644 index 000000000..9aefb5129 --- /dev/null +++ b/app/controllers/helps_controller.rb @@ -0,0 +1,44 @@ +class HelpsController < ApplicationController + before_action :require_login, only: [:feedback] + + helper_method :current_help + + def about + render_ok(content: current_help&.about_us) + end + + def contact + @cooperations = Cooperation.all.group(:user_type) + end + + def cooperatives + @data = { 'alliance_coop' => [], 'com_coop' => [], 'edu_coop' => [] } + @data = @data.merge CooImg.all.group_by(&:img_type) + end + + def agreement + render_ok(content: current_help&.agreement) + end + + def help_center + render_ok(content: current_help&.help_center) + end + + def feedback + content = "

[#{params[:question_kind]}]

问题页面网址:#{params[:url]}

#{params[:description]}" + + ActiveRecord::Base.transaction do + attr = { sender_id: User.current.id, receiver_id: 1, content: content, send_time: Time.now } + PrivateMessage.create!(attr.merge(user_id: User.current.id, target_id: 1, status: 1)) + PrivateMessage.create!(attr.merge(user_id: 1, target_id: User.current.id, status: 0)) + end + + render_ok + end + + private + + def current_help + @_current_help ||= Help.first + end +end \ No newline at end of file diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 37cfed3fb..665eaa294 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -29,7 +29,7 @@ class HomeController < ApplicationController @subjects = Subject.where(homepage_show: 1).includes(:shixuns, :repertoire).limit(8) @tea_users = User.where(homepage_teacher: 1).includes(:user_extension).limit(10).order("experience desc") - @stu_users = User.includes(:user_extension).where(user_extensions: {identity: 1}).limit(10).order("experience desc") + @stu_users = User.where(is_test: 0).includes(:user_extension).where(user_extensions: {identity: 1}).limit(10).order("experience desc") end def search diff --git a/app/controllers/homework_banks_controller.rb b/app/controllers/homework_banks_controller.rb index 7e10509ba..61bded033 100644 --- a/app/controllers/homework_banks_controller.rb +++ b/app/controllers/homework_banks_controller.rb @@ -1,6 +1,6 @@ class HomeworkBanksController < ApplicationController before_action :require_login - before_action :find_bank + before_action :find_bank, :bank_visit_auth before_action :bank_params, only: [:update] before_action :bank_admin, only: [:update, :destroy, :set_public] @@ -44,8 +44,6 @@ class HomeworkBanksController < ApplicationController def find_bank @bank = HomeworkBank.find_by!(id: params[:id]) - tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || - (current_user.certification_teacher? && @bank.is_public) end def bank_admin @@ -57,8 +55,8 @@ class HomeworkBanksController < ApplicationController tip_exception("description参数不能为空") if params[:homework_bank][:description].blank? if @bank.homework_type == 3 tip_exception("base_on_project参数不能为空") if params[:homework_bank][:base_on_project].nil? - tip_exception("min_num参数不能为空") if params[:homework_bank][:min_num].blank? - tip_exception("max_num参数不能为空") if params[:homework_bank][:max_num].blank? + tip_exception("最小人数不能为空") if params[:homework_bank][:min_num].blank? + tip_exception("最大人数参数不能为空") if params[:homework_bank][:max_num].blank? tip_exception("最小人数不能小于1") if params[:homework_bank][:min_num].to_i < 1 tip_exception("最大人数不能小于最小人数") if params[:homework_bank][:max_num].to_i < params[:homework_bank][:min_num].to_i end diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index b62840200..06ee8feee 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -82,7 +82,9 @@ class HomeworkCommonsController < ApplicationController end @task_count = @homework_commons.size - @homework_commons = @homework_commons.order("position DESC").page(page).per(15) + order_str = @homework_type == 4 ? "position DESC" : "IF(ISNULL(homework_commons.publish_time),0,1), homework_commons.publish_time DESC, + homework_commons.created_at DESC" + @homework_commons = @homework_commons.order(order_str).page(page).per(15) if @homework_type == 4 @homework_commons = @homework_commons.includes(:homework_detail_manual, :published_settings, :shixuns) @@ -111,7 +113,7 @@ class HomeworkCommonsController < ApplicationController if @user_course_identity == Course::STUDENT @work = @homework.user_work(current_user.id) # 学生访问列表时计算个人成绩 - if @homework.homework_type == "practice" + if @homework.homework_type == "practice" && !@homework.end_or_late myshixun = Myshixun.find_by(shixun_id: @shixun.id, user_id: current_user.id) if @work && myshixun challenge_settings = @homework.homework_challenge_settings @@ -925,18 +927,10 @@ class HomeworkCommonsController < ApplicationController unless params[:category_id].blank? @category = @course.course_second_categories.find_by(id: params[:category_id], category_type: "shixun_homework") end - ActiveRecord::Base.transaction do - begin - shixuns.each do |shixun| - homework = HomeworksService.new.create_homework shixun, @course, @category, current_user - @homework_ids << homework.id - CreateStudentWorkJob.perform_later(homework.id) - end - rescue Exception => e - uid_logger(e.message) - tip_exception("创建失败") - raise ActiveRecord::Rollback - end + shixuns.each do |shixun| + homework = HomeworksService.new.create_homework shixun, @course, @category, current_user + @homework_ids << homework.id + CreateStudentWorkJob.perform_later(homework.id) end end @@ -1017,29 +1011,21 @@ class HomeworkCommonsController < ApplicationController none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id) course_module = @course.course_modules.find_by(module_type: "shixun_homework") - ActiveRecord::Base.transaction do - begin - subjects.each do |subject| + subjects.each do |subject| - subject.stages.each do |stage| + subject.stages.each do |stage| - # 为实训作业创建与stage同名的子目录 - category = CourseSecondCategory.find_by(name: stage.name, course_id: @course.id, category_type: "shixun_homework") || - 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同名的子目录 + category = CourseSecondCategory.find_by(name: stage.name, course_id: @course.id, category_type: "shixun_homework") || + 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.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) - end - end + # 去掉不对当前用户的单位公开的实训,已发布的实训 + stage.shixuns.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) end - rescue Exception => e - uid_logger(e.message) - tip_exception("创建失败") - raise ActiveRecord::Rollback end end end @@ -1068,7 +1054,7 @@ class HomeworkCommonsController < ApplicationController charge_group_ids = @course.charge_group_ids(current_user) publish_groups = charge_group_ids & params[:group_ids] if params[:group_ids] - ActiveRecord::Base.transaction do + # ActiveRecord::Base.transaction do begin homeworks.each do |homework| # 作业未发布时 @@ -1139,7 +1125,7 @@ class HomeworkCommonsController < ApplicationController tip_exception("发布失败") raise ActiveRecord::Rollback end - end + # end end def end_groups @@ -1168,9 +1154,9 @@ class HomeworkCommonsController < ApplicationController charge_group_ids = @course.charge_group_ids(current_user) end_groups = charge_group_ids & params[:group_ids] if params[:group_ids] - ActiveRecord::Base.transaction do - begin - homeworks.each do |homework| + begin + homeworks.each do |homework| + ActiveRecord::Base.transaction do homework_detail_manual = homework.homework_detail_manual # 分组设置 @@ -1185,7 +1171,7 @@ class HomeworkCommonsController < ApplicationController none_end_settings.update_all(end_time: time) student_works = homework.student_works.where(user_id: course_students.where(course_group_id: none_end_settings. - pluck(:course_group_id)).pluck(:user_id)).has_committed if homework.homework_type == "practice" + pluck(:course_group_id)).pluck(:user_id)).has_committed if homework.homework_type == "practice" homework.end_time = homework.max_group_end_time if homework.end_time > time && homework_detail_manual.try(:comment_status) > 1 @@ -1208,40 +1194,40 @@ class HomeworkCommonsController < ApplicationController 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 + 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 + 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确保是更新后的) - HomeworkEndUpdateScoreJob.perform_later(homework.id) if !homework.allow_late && homework.end_time <= time end end homework.save! end - normal_status(0, "更新成功") - rescue Exception => e - uid_logger(e.message) - tip_exception("操作失败") - raise ActiveRecord::Rollback + HomeworkEndUpdateScoreJob.perform_later(homework.id) if !homework.allow_late && homework.end_time <= time end + normal_status(0, "更新成功") + rescue Exception => e + uid_logger(e.message) + tip_exception("操作失败") + raise ActiveRecord::Rollback end end diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index 69bd01dde..bf067b389 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -25,7 +25,8 @@ class MyshixunsController < ApplicationController begin @shixun = Shixun.select(:id, :identifier, :challenges_count).find(@myshixun.shixun_id) @myshixun.destroy! - StudentWork.where(:myshixun_id => @myshixun.id).update_all(:myshixun_id => 0, :work_status => 0) + StudentWork.where(:myshixun_id => @myshixun.id).update_all(myshixun_id: 0, work_status: 0, work_score: nil, + final_score: nil, efficiency: 0, eff_score: 0, calculation_time: nil, cost_time: 0, compelete_status: 0) rescue Exception => e logger.error("######reset_my_game_failed:#{e.message}") raise("ActiveRecord::RecordInvalid") @@ -266,10 +267,15 @@ class MyshixunsController < ApplicationController :identifier => @sec_key, :exec_time => exec_time) uid_logger("-- game build: file update #{@sec_key}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}") end - unless @hide_code + # 隐藏代码文件 和 VNC的都不需要走版本库 + unless @hide_code || @myshixun.shixun&.vnc_evaluate # 远程版本库文件内容 last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] - content = params[:content] + content = if @myshixun.mirror_name.select {|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? + params[:content].gsub(/\t/, ' ').gsub(/ /, ' ') # 这个不是空格,在windows机器上带来的问题 + else + params[:content] + end Rails.logger.info("###11222333####{content}") Rails.logger.info("###222333####{last_content}") diff --git a/app/controllers/project_packages_controller.rb b/app/controllers/project_packages_controller.rb index 3cc7e79cb..c8b010b32 100644 --- a/app/controllers/project_packages_controller.rb +++ b/app/controllers/project_packages_controller.rb @@ -55,7 +55,7 @@ class ProjectPackagesController < ApplicationController package.destroy! - Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, container_id: package.id, + Tiding.create!(user_id: package.creator_id, trigger_user_id: 0, container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Destroyed', extra: package.title) render_ok diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb index f09a53dbe..60b9a807c 100644 --- a/app/controllers/question_banks_controller.rb +++ b/app/controllers/question_banks_controller.rb @@ -88,7 +88,7 @@ class QuestionBanksController < ApplicationController end def send_to_course - banks = object_banks + banks = @object_type.classify.constantize.where(id: params[:object_id]) course = current_user.manage_courses.find_by!(id: params[:course_id]) banks.each do |bank| case @object_type @@ -264,7 +264,9 @@ class QuestionBanksController < ApplicationController # new_exercise.create_exercise_list # exercise.update_column(:quotes, exercise.quotes+1) # end - new_exercise if new_exercise.save! + new_exercise.save! + exercise.update_column(:quotes, exercise.quotes+1) + new_exercise end end @@ -291,7 +293,9 @@ class QuestionBanksController < ApplicationController # new_poll.create_polls_list # poll.update_column(:quotes, poll.quotes+1) # end - new_poll if new_poll.save! + new_poll.save! + poll.update_column(:quotes, poll.quotes+1) + new_poll end end diff --git a/app/controllers/shixun_lists_controller.rb b/app/controllers/shixun_lists_controller.rb new file mode 100644 index 000000000..e92e857ad --- /dev/null +++ b/app/controllers/shixun_lists_controller.rb @@ -0,0 +1,10 @@ +class ShixunListsController < ApplicationController + def index + @results = ShixunSearchService.call(search_params) + end + + private + def search_params + params.permit(:keyword, :type, :page, :limit, :order, :type, :status, :diff) + end +end \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index b47a9a346..8a120d6bd 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -1,6 +1,7 @@ class ShixunsController < ApplicationController include ShixunsHelper include ApplicationHelper + include ElasticsearchAble before_action :require_login, :check_auth, except: [:download_file, :index, :menus, :show, :show_right, :ranking_list, :discusses, :collaborators, :fork_list, :propaedeutics] @@ -121,25 +122,28 @@ class ShixunsController < ApplicationController @shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1]) end - ## 搜索关键字创建者、实训名称、院校名称 - unless params[:search].blank? - keyword = params[:search].strip - @shixuns = @shixuns.joins(user: [user_extension: :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]) + @shixuns = @shixuns.where(trainee: params[:diff]) end - @total_count = @shixuns.count page = params[:page] || 1 - limit = params[:limit] || 15 - - @shixuns = @shixuns.order("myshixuns_count desc").page(page).per(limit).includes(:shixun_info, :subjects, user: [user_extension: :school]) + limit = params[:limit] || 10 + offset = (page.to_i - 1) * (limit.to_i) + order = params[:order] || "desc" + ## 搜索关键字创建者、实训名称、院校名称 + keyword = params[:keyword].to_s.strip.presence || '*' + + model_options = { + index_name: [Shixun], + model_includes: Shixun.searchable_includes + } + model_options.merge(where: { id: @shixuns.pluck(:id) }).merge(order: {"myshixuns_count" => order}).merge(limit: limit, offset: offset) + model_options.merge(default_options) + @shixuns = Searchkick.search(keyword, model_options) + # @shixuns = Shixun.search keyword, where: {id: @shixuns.pluck(:id)}, order: {"myshixuns_count" => order}, limit: limit, offset: offset + + @total_count = @shixuns.total_count end ## 获取顶部菜单 @@ -225,6 +229,16 @@ class ShixunsController < ApplicationController evaluate_script: @shixun.evaluate_script) end + # 同步私密版本库 + if @shixun.shixun_secret_repository + repo_name = "#{current_user.login}/secret_#{@shixun.identifier}" + fork_repository_name = "#{current_user.login}/secret_#{@new_shixun.identifier}" + ShixunSecretRepository.create!(shixun_id: @new_shixun.id, + repo_name: "#{repo_name}", + secret_dir_path: @shixun.shixun_secret_repository.secret_dir_path) + GitService.fork_repository(repo_path: "#{repo_name}.git", fork_repository_path: (fork_repository_name + ".git")) + end + # 同步镜像 if @shixun.mirror_repositories.present? @shixun.mirror_repositories.each do |mirror| @@ -453,6 +467,7 @@ class ShixunsController < ApplicationController ShixunMirrorRepository.create(:shixun_id => @shixun.id, :mirror_repository_id => mirror) end end + logger.info("#########shixun_params#{shixun_params}") @shixun.update_attributes(shixun_params) logger.info("##########shixun_info_params: #{shixun_info_params}") logger.info("##########params[:shixun_info][:evaluate_script]: #{params[:shixun_info][:evaluate_script]}") @@ -468,17 +483,31 @@ class ShixunsController < ApplicationController ShixunSchool.create!(arr) end # 超级管理员和运营人员才能保存 中间层服务器pod信息的配置 - if current_user.admin? || current_user.business? + # 如果镜像改动了,则也需要更改 + mirror = @shixun.shixun_service_configs.map(&:mirror_repository_id).sort + new_mirror = params[:shixun_service_configs].map{|c| c[:mirror_repository_id]}.sort + if current_user.admin? || current_user.business? || (mirror != new_mirror) @shixun.shixun_service_configs.destroy_all service_config_params[:shixun_service_configs].each do |config| - logger.info("####{config[:mirror_repository_id]}") name = MirrorRepository.find_by_id(config[:mirror_repository_id])&.name # 不保存没有镜像的配置 @shixun.shixun_service_configs.create!(config) if name.present? end end + # 添加第二仓库 + if params[:is_secret_repository] + add_secret_repository + else + # 如果有仓库,就要删 + if @shixun.shixun_secret_repository&.repo_name + @shixun.shixun_secret_repository.lock! + GitService.delete_repository(repo_path: @shixun.shixun_secret_repository.repo_path) + @shixun.shixun_secret_repository.destroy + end + end + rescue Exception => e - uid_logger_error(e.message) + uid_logger_error("实训保存失败--------#{e.message}") tip_exception("实训保存失败") raise ActiveRecord::Rollback end @@ -823,6 +852,30 @@ class ShixunsController < ApplicationController end end + # 设置私密版本库的在tpm中的目录 + def set_secret_dir + raise("设置路径不能为空") if params[:secret_dir_path].blank? + raise("请先配置私密版本库") if @shixun.shixun_secret_repository.blank? + @shixun.shixun_secret_repository.update_attributes(:secret_dir_path => params[:secret_dir_path]) + normal_status("设置成功") + end + + def secret_repository + begin + @repo_path = @shixun.shixun_secret_repository&.repo_path + @repo_url = repo_url @repo_path + @trees = GitService.file_tree(repo_path: @repo_path, path: params[:path]) + logger.info("#11@@#@#@#@111#@@@@###{@trees}") + if @trees + logger.info("#@@#@#@#@#@@@@###{@trees.try(:count)}") + @latest_commit = [GitService.commits(repo_path: @repo_path).first] + Rails.logger.info("########## #{@latest_commit}") + end + rescue Exception => e + logger.error(e.message) + end + end + include GitCommon def update_file @@ -936,7 +989,7 @@ private raise("实训名称不能为空") if params[:shixun][:name].blank? params.require(:shixun).permit(:name, :trainee, :webssh, :can_copy, :use_scope, :vnc, :test_set_permission, :task_pass, :multi_webssh, :opening_time, :mirror_script_id, :code_hidden, - :hide_code, :forbid_copy) + :hide_code, :forbid_copy, :vnc_evaluate, :code_edit_permission) end def shixun_info_params @@ -959,7 +1012,13 @@ private end def find_repo_name - @repo_path = @shixun.try(:repo_path) + # 有私密版本库的参数时,需要拿私密仓库 + @repo_path = if params[:secret_repository] + @shixun.shixun_secret_repository&.repo_path + else + @shixun.try(:repo_path) + end + logger.info("######{@repo_path}") @path = params[:path] end @@ -994,4 +1053,13 @@ private modify_shixun = ShixunModify.exists?(:myshixun_id => current_myshixun.id, :shixun_id => @shixun.id, :status => 1) games.size != min_challenges.size || modify_shixun end + + # 添加私密仓库 + def add_secret_repository + # 防止跟tpm版本库重名,加了前缀secret + repo_path = repo_namespace(current_user.login, "secret_#{@shixun.identifier}") + GitService.add_repository(repo_path: repo_path) + ShixunSecretRepository.create!(repo_name: repo_path.split(".")[0], shixun_id: @shixun.id) + end + end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index 99a02106c..ab62cbd45 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -8,12 +8,15 @@ class StudentWorksController < ApplicationController before_action :find_work, only: [:shixun_work_report, :adjust_review_score, :shixun_work, :commit_des, :update_des, :adjust_score, :show, :adjust_score, :supply_attachments, :revise_attachment, :comment_list, :add_score, :add_score_reply, :destroy_score, :appeal_anonymous_score, - :deal_appeal_score, :cancel_appeal, :edit, :update, :export_shixun_work_report] + :deal_appeal_score, :cancel_appeal, :edit, :update, :export_shixun_work_report, + :shixun_work_comment, :destroy_work_comment] before_action :user_course_identity before_action :allow_add_score, only: [:add_score] before_action :homework_publish - before_action :teacher_allowed, only: [:adjust_score, :adjust_review_score, :deal_appeal_score] + before_action :teacher_allowed, only: [:adjust_score, :adjust_review_score, :deal_appeal_score, :shixun_work_comment, + :destroy_work_comment] + before_action :course_student, only: [:new, :commit_des, :update_des, :create, :edit, :update, :search_member_list, :relate_project, :cancel_relate_project, :relate_project, :delete_work] @@ -455,6 +458,7 @@ class StudentWorksController < ApplicationController @shixun = @homework.shixuns.take # 提示: 这里如果includes outputs表的话: sum(:evaluate_count)会出现错误 @games = @work.myshixun.games.joins(:challenge).reorder("challenges.position asc") if @work.myshixun + @comment = @work.shixun_work_comments.find_by(challenge_id: 0) # 用户最大评测次数 if @games @@ -468,6 +472,41 @@ class StudentWorksController < ApplicationController @echart_data = student_efficiency(@homework, @work) end + # 实训作品的评阅 + def shixun_work_comment + tip_exception("请至少输入一个评阅") if params[:comment].blank? && params[:hidden_comment].blank? + ActiveRecord::Base.transaction do + challenge = @homework.shixuns.first&.challenges.find_by(id: params[:challenge_id]) unless params[:challenge_id].blank? + if challenge.present? + @comment = @work.shixun_work_comments.find_by(challenge_id: challenge.id) || + ShixunWorkComment.new(student_work_id: @work.id, user_id: current_user.id, challenge_id: challenge.id) + else + @comment = @work.shixun_work_comments.find_by(challenge_id: 0) || + ShixunWorkComment.new(student_work_id: @work.id, user_id: current_user.id, challenge_id: 0) + end + @comment.comment = params[:comment] + @comment.hidden_comment = params[:hidden_comment] + @comment.save! + end + end + + # 删除实训作品评阅 + def destroy_work_comment + ActiveRecord::Base.transaction do + # tip_exception("visible_comment参数有误") if params[:visible_comment].nil? + + comment = @work.shixun_work_comments.find_by!(id: params[:comment_id]) + comment.destroy! + # params[:visible_comment] ? comment.comment = nil : comment.hidden_comment = nil + # if comment.comment.nil? && comment.hidden_comment.nil? + # comment.destroy! + # else + # comment.save! + # end + normal_status("删除成功") + end + end + def export_shixun_work_report @user = @work.user @shixun = @homework.shixuns.take diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 7c76748b1..36f14a5d5 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -203,26 +203,24 @@ class SubjectsController < ApplicationController stages = @subject.stages.where(id: @subject.stage_shixuns.where(shixun_id: params[:shixun_ids]).pluck(:stage_id)) course_module = @course.course_modules.where(module_type: "shixun_homework").first + homework_ids = [] ActiveRecord::Base.transaction do - begin - # 将实训课程下的所有已发布实训按顺序发送到课堂,同时创建与章节同名的实训作业目录 - stages.each do |stage| - category = CourseSecondCategory.where(name: stage.name, course_id: @course.id, category_type: "shixun_homework").first || - 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| - homework = HomeworksService.new.create_homework shixun, @course, category, current_user - CreateStudentWorkJob.perform_later(homework.id) - end + # 将实训课程下的所有已发布实训按顺序发送到课堂,同时创建与章节同名的实训作业目录 + stages.each do |stage| + category = CourseSecondCategory.where(name: stage.name, course_id: @course.id, category_type: "shixun_homework").first || + 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| + homework = HomeworksService.new.create_homework shixun, @course, category, current_user + homework_ids << homework.id end - rescue Exception => e - uid_logger(e.message) - tip_exception(e.message) - raise ActiveRecord::Rollback end end + homework_ids.each do |homework_id| + CreateStudentWorkJob.perform_later(homework_id) + end end def publish @@ -442,8 +440,8 @@ class SubjectsController < ApplicationController # 用户进展和获取的标签 def user_subject_progress challenge_ids pass_games = Game.select(:id, :cost_time, :challenge_id).where(status: 2, user_id: current_user.id, challenge_id: challenge_ids) if current_user.logged? - @all_score = Challenge.where(id: challenge_ids).sum(:score) + @all_score = Challenge.where(id: challenge_ids).size # 如果没有通关的,没必要再继续统计了 if pass_games.blank? @my_score = 0 @@ -452,15 +450,15 @@ class SubjectsController < ApplicationController @user_tags = [] else pass_challenge_ids = pass_games.map(&:challenge_id).uniq # 按道理是不用去重的,但是历史数据与重复 - subject_challenge_count = @subject.shixuns.sum(:challenges_count) + # subject_challenge_count = @subject.shixuns.sum(:challenges_count) # 用户通关获得的标签 @user_tags = ChallengeTag.where(challenge_id: pass_challenge_ids).pluck(:name) # 用户学习进度 @learned = - subject_challenge_count == 0 ? 0 : - ((pass_challenge_ids.size.to_f / subject_challenge_count).round(2) * 100).to_i + @all_score == 0 ? 0 : + ((pass_challenge_ids.size.to_f / @all_score).round(2) * 100).to_i # 用户通关分数 - @my_score = Challenge.where(id: pass_challenge_ids).pluck(:score).sum + @my_score = Challenge.where(id: pass_challenge_ids).size @time = pass_games.map(&:cost_time).sum end diff --git a/app/controllers/task_banks_controller.rb b/app/controllers/task_banks_controller.rb index e2e7f0a1a..2b1a400ef 100644 --- a/app/controllers/task_banks_controller.rb +++ b/app/controllers/task_banks_controller.rb @@ -1,6 +1,7 @@ class TaskBanksController < ApplicationController before_action :require_login - before_action :find_bank + before_action :find_bank, :bank_visit_auth + before_action :bank_visit_auth before_action :bank_admin, only: [:update] def show @@ -25,8 +26,6 @@ class TaskBanksController < ApplicationController def find_bank @bank = GtaskBank.find_by!(id: params[:id]) - tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin? || - (current_user.certification_teacher? && @bank.is_public) end def bank_admin @@ -36,14 +35,17 @@ class TaskBanksController < ApplicationController def gtask_bank_params tip_exception("name参数不能为空") if params[:gtask_bank][:name].blank? tip_exception("description参数不能为空") if params[:gtask_bank][:description].blank? - if @bank.homework_type == 3 + if @bank.task_type == 2 tip_exception("base_on_project参数不能为空") if params[:gtask_bank][:base_on_project].nil? tip_exception("min_num参数不能为空") if params[:gtask_bank][:min_num].blank? tip_exception("max_num参数不能为空") if params[:gtask_bank][:max_num].blank? tip_exception("最小人数不能小于1") if params[:gtask_bank][:min_num].to_i < 1 tip_exception("最大人数不能小于最小人数") if params[:gtask_bank][:max_num].to_i < params[:gtask_bank][:min_num].to_i end - params.require(:gtask_bank).permit(:name, :description) if @bank.task_type == 1 - params.require(:gtask_bank).permit(:name, :description, :min_num, :max_num, :base_on_project) if @bank.task_type == 2 + if @bank.task_type == 1 + params.require(:gtask_bank).permit(:name, :description) + else + params.require(:gtask_bank).permit(:name, :description, :min_num, :max_num, :base_on_project) + end end end diff --git a/app/controllers/users/question_banks_controller.rb b/app/controllers/users/question_banks_controller.rb index d6a2fcc88..c5b837d0b 100644 --- a/app/controllers/users/question_banks_controller.rb +++ b/app/controllers/users/question_banks_controller.rb @@ -1,11 +1,12 @@ class Users::QuestionBanksController < Users::BaseController before_action :require_login - before_action :private_user_resources! + skip_before_action :check_observed_user_exists! + # before_action :private_user_resources! before_action :check_query_params! before_action :check_user_permission! def index - service = Users::QuestionBankService.new(observed_user, query_params) + service = Users::QuestionBankService.new(User.current, query_params) question_banks = service.call @count = question_banks.count @@ -30,7 +31,7 @@ class Users::QuestionBanksController < Users::BaseController .where(commit_status: 1, exercises: { exercise_bank_id: question_bank_ids }) .group('exercises.exercise_bank_id').count when 'poll' then - PollUser.joins(:poll).where(polls: { exercise_bank_id: question_bank_ids }) + PollUser.joins(:poll).where(commit_status: 1, polls: { exercise_bank_id: question_bank_ids }) .group('polls.exercise_bank_id').count when 'gtask' then GraduationWork.has_committed.joins(:graduation_task) @@ -65,7 +66,7 @@ class Users::QuestionBanksController < Users::BaseController def check_user_permission! if params[:type] == 'publicly' - render_error("未通过职业认证") unless User.current.admin? || User.current.certification_teacher? + normal_status(-2,"未通过职业认证") unless User.current.admin? || User.current.certification_teacher? else render_forbidden unless User.current.admin? || User.current.is_teacher? end diff --git a/app/controllers/wechats/js_sdk_signatures_controller.rb b/app/controllers/wechats/js_sdk_signatures_controller.rb index 6d7b3d87d..0b66cc263 100644 --- a/app/controllers/wechats/js_sdk_signatures_controller.rb +++ b/app/controllers/wechats/js_sdk_signatures_controller.rb @@ -1,6 +1,6 @@ class Wechats::JsSdkSignaturesController < ApplicationController def create - timestamp = (Time.now.to_f * 1000).to_i + timestamp = Time.now.to_i noncestr = ('A'..'z').to_a.sample(8).join signature = Util::Wechat.js_sdk_signature(params[:url], noncestr, timestamp) diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 81093dc12..df642a074 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -86,7 +86,7 @@ module TidingDecorator def teacher_join_course_content name = Course.find_by(id: container_id)&.name - I18n.t(locale_format extra) % [user.show_real_name, name] + I18n.t(locale_format extra) % [trigger_user&.show_real_name, name] end def apply_add_department_content @@ -258,7 +258,7 @@ module TidingDecorator def manager_join_project_content project = Project.find_by(id: container_id) - I18n.t(locale_format(extra)) % [user&.show_real_name, project.name] + I18n.t(locale_format(extra)) % [trigger_user&.show_real_name, project.name] end def reporter_join_project_content diff --git a/app/helpers/admins/base_helper.rb b/app/helpers/admins/base_helper.rb index c655be2e7..d79456ac8 100644 --- a/app/helpers/admins/base_helper.rb +++ b/app/helpers/admins/base_helper.rb @@ -18,7 +18,7 @@ module Admins::BaseHelper def sidebar_item(url, text, **opts) content = link_to url, 'data-controller': opts[:controller] do - content_tag(:i, '', class: "fa fa-#{opts[:icon]}", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + + content_tag(:i, '', class: "fa fa-#{opts[:icon]} fa-fw", 'data-toggle': 'tooltip', 'data-placement': 'right', 'data-boundary': 'window', title: text) + content_tag(:span, text) end @@ -87,16 +87,24 @@ module Admins::BaseHelper raw link_to(name, url, { method: :post, remote: true, class: klass, 'data-confirm': '确认审核通过?'}.merge(opts)) end - def delete_link(name, url, **opts) + def delete_link(name, url, **opts, &block) klass = ['action delete-action', opts.delete(:class)].compact.join(' ') refresh_url_data = "refresh_url=#{CGI::escape(request.fullpath)}" url = url + (url.index('?') ? '&' : '?') + refresh_url_data - raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts)) + if block_given? + raw link_to(url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts), &block) + else + raw link_to(name, url, { method: :delete, remote: true, class: klass, 'data-confirm': '确认删除?'}.merge(opts)) + end end def unsafe_params params.except(:controller, :action).to_unsafe_h end + + def list_index_no(page,index) + (page - 1) * 20 + index + 1 + end end \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 44169dc59..d889de36d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -56,11 +56,6 @@ module ApplicationHelper end - # 相关推荐 - def relation_path(shixun) - shixun.subjects.where(hidden: 0).limit(2) - end - # shixun开启挑战对应的行为名及url def task_operation_url current_myshixun, shixun if current_myshixun.blank? diff --git a/app/helpers/course_stages_helper.rb b/app/helpers/course_stages_helper.rb new file mode 100644 index 000000000..7ebb68d9a --- /dev/null +++ b/app/helpers/course_stages_helper.rb @@ -0,0 +1,2 @@ +module CourseStagesHelper +end diff --git a/app/helpers/courses_helper.rb b/app/helpers/courses_helper.rb index 83c4ded65..5ca4eb773 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -110,6 +110,8 @@ module CoursesHelper course.course_groups_count when "announcement" course.informs.count + when "online_learning" + course.shixuns.count end end @@ -267,10 +269,10 @@ module CoursesHelper group_info end - def last_subject_shixun user_id, subject - myshixun = Myshixun.where(user_id: user_id, shixun_id: subject&.shixuns).order("updated_at desc").first + def last_subject_shixun user_id, course + myshixun = Myshixun.where(user_id: user_id, shixun_id: course.shixuns).order("updated_at desc").first return "" unless myshixun - stage_shixun = subject&.stage_shixuns.where(shixun_id: myshixun.shixun_id).take - progress = stage_shixun&.stage&.position.to_s + "-" + stage_shixun&.position.to_s + " " + myshixun.shixun&.name + stage_shixun = course.course_stage_shixuns.where(shixun_id: myshixun.shixun_id).take + progress = stage_shixun&.course_stage&.position.to_s + "-" + stage_shixun&.position.to_s + " " + myshixun.shixun&.name end end diff --git a/app/helpers/exercises_helper.rb b/app/helpers/exercises_helper.rb index 2c417ea74..98a580ecc 100644 --- a/app/helpers/exercises_helper.rb +++ b/app/helpers/exercises_helper.rb @@ -16,18 +16,26 @@ module ExercisesHelper end if q_type <= Exercise::JUDGMENT - if answers_content.present? #学生有回答时 - answer_choice_array = [] - answers_content.each do |a| - answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 - end - user_answer_content = answer_choice_array.sort - standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 - if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 - ques_score = q.question_score - else - ques_score = 0.0 - end + if answers_content.present? #学生有回答时,分数已经全部存到exercise_answer 表,所以可以直接取第一个值 + ques_score = answers_content.first.score + ques_score = ques_score < 0 ? 0.0 : ques_score + # answer_choice_array = [] + # answers_content.each do |a| + # answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 + # end + # user_answer_content = answer_choice_array.sort + # standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 + # if q_type == Exercise::MULTIPLE && standard_answer.size == 1 # 老数据的问题 + # ques_score = answers_content.first.score + # else + # + # end + + # if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 + # ques_score = q.question_score + # else + # ques_score = 0.0 + # end else ques_score = 0.0 end @@ -58,7 +66,6 @@ module ExercisesHelper exercise_sub_status.each do |s| sub_answer = s.exercise_answers.search_answer_users("user_id",user_id) #主观题只有一个回答 if sub_answer.present? && sub_answer.first.score >= 0.0 - if s.question_score <= sub_answer.first.score stand_status = 1 else @@ -775,22 +782,24 @@ module ExercisesHelper user_score = user_score_pre.present? ? user_score_pre.pluck(:score).sum : nil elsif ques_type == 5 || ques_type == 3 user_score = user_score_pre.present? ? user_score_pre.pluck(:score).sum : 0.0 - else - if exercise_answers.present? #判断题和选择题时, - answer_choice_array = [] - exercise_answers.each do |a| - answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 - end - user_answer_content = answer_choice_array.sort - standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 - if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 - user_score = q.question_score - else - user_score = 0.0 - end - else - user_score = 0.0 - end + else #选择题,判断题根据第一个记录查分 + user_score = user_score_pre.present? ? user_score_pre.first.score : 0.0 + + # if exercise_answers.present? #判断题和选择题时, + # answer_choice_array = [] + # exercise_answers.each do |a| + # answer_choice_array.push(a.exercise_choice.choice_position) #学生答案的位置 + # end + # user_answer_content = answer_choice_array.sort + # standard_answer = q.exercise_standard_answers.pluck(:exercise_choice_id).sort #该问题的标准答案,可能有多个 + # if user_answer_content == standard_answer #答案一致,多选或单选才给分,答案不对不给分 + # user_score = q.question_score + # else + # user_score = 0.0 + # end + # else + # user_score = 0.0 + # end end end diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb index f17ede53c..05b1b2f8b 100644 --- a/app/helpers/export_helper.rb +++ b/app/helpers/export_helper.rb @@ -113,7 +113,7 @@ module ExportHelper end else #实训题 shixun = homework.shixuns.first - shixun_head_cells = %w(完成情况 通关时间 总耗时 总评测次数 获得经验值 关卡得分) + shixun_head_cells = %w(完成情况 通关时间 学员在EduCoder做实训花费的时间 总评测次数 获得经验值 关卡得分) eff_boolean = homework.work_efficiency if eff_boolean eff_score_cell = ["效率分"] @@ -123,7 +123,7 @@ module ExportHelper if allow_late_boolean #允许迟交 eff_score_cell.push("迟交扣分") end - shixun_time_cells = %w(最终成绩 更新时间 提交耗时 评语) + shixun_time_cells = %w(最终成绩 更新时间 作业发布到学员完成作业所耗的时间 评语) @work_head_cells = (head_cells_format + shixun_head_cells + eff_score_cell + shixun_time_cells).reject(&:blank?) works.includes(:student_works_scores, user: :user_extension, myshixun: :games).each_with_index do |w, index| myshixun = w.try(:myshixun) @@ -163,7 +163,8 @@ module ExportHelper end w_15 = w.work_score.nil? ? "--" : w.work_score.round(1) w_16 = w.update_time ? format_time(w.update_time) : "--" "更新时间" - w_17 = w.cost_time ? (game_spend_time w.cost_time) : "--" + myshixun_complete = myshixun && myshixun.status == 1 + w_17 = myshixun_complete && w.cost_time ? (game_spend_time w.cost_time) : "未完成" teacher_comments = w.student_works_scores if teacher_comments.present? w_18 = "" diff --git a/app/helpers/homework_commons_helper.rb b/app/helpers/homework_commons_helper.rb index a3ed43405..cc23d05d6 100644 --- a/app/helpers/homework_commons_helper.rb +++ b/app/helpers/homework_commons_helper.rb @@ -237,4 +237,14 @@ module HomeworkCommonsHelper def anon_comments user, work_id StudentWorksScore.where(student_work_id: work_id, reviewer_role: 3, user_id: user.id) end + + def student_redo_work work, homework + status = false + publish_time = homework.homework_group_setting(work.user_id)&.publish_time + if work.myshixun && publish_time && work.myshixun.created_at < publish_time && work.myshixun.games.where("answer_open > 0").count > 0 + min_time = Grade.where(container_type: "Answer", container_id: work.myshixun.games.where("answer_open > 0").pluck(:id)).pluck(:created_at).min + status = min_time && min_time < publish_time + end + status + end end diff --git a/app/libs/util/file_manage.rb b/app/libs/util/file_manage.rb index 620fd7f01..f592ca4e7 100644 --- a/app/libs/util/file_manage.rb +++ b/app/libs/util/file_manage.rb @@ -10,10 +10,18 @@ module Util::FileManage File.join(Rails.root, "public", "images", relative_path) end - def disk_filename(source_type,source_id,image_file=nil) + def disk_filename(source_type, source_id,image_file=nil) File.join(storage_path, "#{source_type}", "#{source_id}") end + def exist?(source_type, source_id) + File.exist?(disk_filename(source_type, source_id)) + end + + def disk_file_url(source_type, source_id) + File.join('/images', relative_path, "#{source_type}", "#{source_id}") + end + def disk_auth_filename(source_type, source_id, type) File.join(storage_path, "#{source_type}", "#{source_id}#{type}") end diff --git a/app/libs/util/wechat.rb b/app/libs/util/wechat.rb index 069322f18..1b064ba94 100644 --- a/app/libs/util/wechat.rb +++ b/app/libs/util/wechat.rb @@ -7,7 +7,8 @@ module Util::Wechat attr_accessor :appid, :secret def js_sdk_signature(url, noncestr, timestamp) - str = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url }.to_query + data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url } + str = data.map { |k, v| "#{k}=#{v}" }.join('&') Digest::SHA1.hexdigest(str) end diff --git a/app/models/apply_add_school.rb b/app/models/apply_add_school.rb index c303283ca..ac7c880cd 100644 --- a/app/models/apply_add_school.rb +++ b/app/models/apply_add_school.rb @@ -1,10 +1,12 @@ class ApplyAddSchool < ApplicationRecord belongs_to :school + belongs_to :user has_many :applied_messages, as: :applied has_many :tidings, as: :container, dependent: :destroy after_create :send_notify + # after_destroy :after_delete_apply private @@ -12,4 +14,9 @@ class ApplyAddSchool < ApplicationRecord Tiding.create!(user_id: 1, status: 0, container_id: id, container_type: 'ApplyAddSchools', trigger_user_id: user_id, belong_container: school, tiding_type: 'Apply') end + + # def after_delete_apply + # + # end + end \ No newline at end of file diff --git a/app/models/attachment.rb b/app/models/attachment.rb index e3c55242f..ae28e7d52 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -4,7 +4,7 @@ class Attachment < ApplicationRecord include Publishable include Lockable - belongs_to :container, polymorphic: true, touch: true, optional: true + belongs_to :container, polymorphic: true, optional: true belongs_to :author, class_name: "User", foreign_key: :author_id belongs_to :course, foreign_key: :container_id, optional: true has_many :attachment_group_settings, :dependent => :destroy diff --git a/app/models/coo_img.rb b/app/models/coo_img.rb new file mode 100644 index 000000000..0766c0727 --- /dev/null +++ b/app/models/coo_img.rb @@ -0,0 +1,5 @@ +class CooImg < ApplicationRecord + extend Enumerize + + enumerize :img_type, in: %i[com_coop edu_coop alliance_coop] +end \ No newline at end of file diff --git a/app/models/cooperation.rb b/app/models/cooperation.rb new file mode 100644 index 000000000..f0eb30cf6 --- /dev/null +++ b/app/models/cooperation.rb @@ -0,0 +1,9 @@ +class Cooperation < ApplicationRecord + def user_type_text + case user_type.to_i + when 1 then '高校合作' + when 2 then '企业合作' + when 3 then '实训投稿' + end + end +end \ No newline at end of file diff --git a/app/models/course.rb b/app/models/course.rb index 5a2a065ba..ba818449e 100644 --- a/app/models/course.rb +++ b/app/models/course.rb @@ -70,6 +70,11 @@ class Course < ApplicationRecord has_many :course_acts, class_name: 'CourseActivity', as: :course_act, dependent: :destroy has_many :tidings, as: :container, dependent: :destroy + # 开放课堂 + has_many :course_stages, -> { order("course_stages.position ASC") }, dependent: :destroy + has_many :course_stage_shixuns, dependent: :destroy + has_many :shixuns, through: :course_stage_shixuns + # 老版的members弃用 现用course_members has_many :members @@ -77,6 +82,7 @@ class Course < ApplicationRecord scope :ended, ->(is_end = true) { where(is_end: is_end) } scope :processing, -> { where(is_end: false) } scope :not_deleted, -> { where(is_delete: 0) } + scope :not_excellent, -> { where(excellent: 0) } scope :deleted, ->(is_delete = 1) { where(is_delete: is_delete) } scope :by_user, ->(user) { joins(:course_members).where('course_members.user_id = ?', user.id).order(updated_at: :desc) } scope :by_keywords, lambda { |keywords| @@ -333,11 +339,33 @@ class Course < ApplicationRecord teacher_power_courses end + def create_stages subject + if subject + subject.stages.each do |stage| + new_stage = CourseStage.create!(course_id: id, name: stage.name, description: stage.description, position: stage.position) + stage.stage_shixuns.each do |stage_shixun| + CourseStageShixun.create!(course_id: id, course_stage_id: new_stage.id, shixun_id: stage_shixun.shixun_id, position: stage_shixun.position) + end + end + end + end + + def learning? user_id + Myshixun.where(user_id: user_id, shixun_id: shixuns).exists? + end + + def my_subject_progress + my_challenge_count = Game.joins(:challenge).where(user_id: User.current.id, status: 2, challenges: {shixun_id: shixuns.published_closed}). + pluck(:challenge_id).uniq.size + course_challeng_count = shixuns.pluck(:challenges_count).sum + count = course_challeng_count == 0 ? 0 : ((my_challenge_count.to_f / course_challeng_count).round(2) * 100).to_i + end + private #创建课程后,给该用户发送消息 def send_tiding - self.tidings << Tiding.new(user_id: tea_id, trigger_user_id: 1, belong_container_id: id, + self.tidings << Tiding.new(user_id: tea_id, trigger_user_id: 0, belong_container_id: id, belong_container_type: 'Course', tiding_type: 'System') end diff --git a/app/models/course_message.rb b/app/models/course_message.rb index 674e92169..7774dbf0c 100644 --- a/app/models/course_message.rb +++ b/app/models/course_message.rb @@ -28,7 +28,7 @@ class CourseMessage < ApplicationRecord def send_deal_tiding deal_status # 发送申请处理结果消息 Tiding.create!( - user_id: course_message_id, trigger_user_id: 1, container_id: course_id, container_type: 'DealCourse', + user_id: course_message_id, trigger_user_id: 0, container_id: course_id, container_type: 'DealCourse', belong_container: course, extra: content.to_i == 2 ? '9' : '7', tiding_type: 'System', status: deal_status ) # 将申请消息置为已处理 diff --git a/app/models/course_stage.rb b/app/models/course_stage.rb new file mode 100644 index 000000000..f105e25f6 --- /dev/null +++ b/app/models/course_stage.rb @@ -0,0 +1,9 @@ +class CourseStage < ApplicationRecord + belongs_to :course + + has_many :course_stage_shixuns, -> { order("course_stage_shixuns.position ASC") }, dependent: :destroy + has_many :shixuns, :through => :course_stage_shixuns + + validates :name, length: { maximum: 60 } + validates :description, length: { maximum: 300 } +end diff --git a/app/models/course_stage_shixun.rb b/app/models/course_stage_shixun.rb new file mode 100644 index 000000000..6ab2707a4 --- /dev/null +++ b/app/models/course_stage_shixun.rb @@ -0,0 +1,5 @@ +class CourseStageShixun < ApplicationRecord + belongs_to :course + belongs_to :course_stage, counter_cache: :shixuns_count + belongs_to :shixun +end diff --git a/app/models/ec_discipline.rb b/app/models/ec_discipline.rb new file mode 100644 index 000000000..449098ce1 --- /dev/null +++ b/app/models/ec_discipline.rb @@ -0,0 +1,12 @@ +class EcDiscipline < ActiveRecord::Base + validates_presence_of :code, :name + + has_many :ec_discipline_firsts + + # 专业数目 + def major_count + count = 0 + self.ec_discipline_firsts.map{|f| count += f.ec_majors.count} + count + end +end diff --git a/app/models/ec_discipline_first.rb b/app/models/ec_discipline_first.rb new file mode 100644 index 000000000..7c111d2c9 --- /dev/null +++ b/app/models/ec_discipline_first.rb @@ -0,0 +1,6 @@ +class EcDisciplineFirst < ActiveRecord::Base + validates_presence_of :code, :name + + has_many :ec_majors + belongs_to :ec_discipline +end diff --git a/app/models/ec_major.rb b/app/models/ec_major.rb index 4842f7d70..ae854a4c8 100644 --- a/app/models/ec_major.rb +++ b/app/models/ec_major.rb @@ -1,7 +1,10 @@ class EcMajor < ApplicationRecord # 主页对应的学校,不同学校可以选用同样的专业,而每个专业又各具特色 - has_many :schools, through: :ec_major_schools has_many :ec_major_schools, dependent: :destroy + has_many :schools, through: :ec_major_schools + + # 一级专业 + belongs_to :ec_discipline_first scope :search_name_or_code, -> (keyword) { where('name LIKE :keyword OR code LIKE :keyword', keyword: "%#{keyword.strip}%") } end diff --git a/app/models/ec_template.rb b/app/models/ec_template.rb new file mode 100644 index 000000000..36f5ae305 --- /dev/null +++ b/app/models/ec_template.rb @@ -0,0 +1,6 @@ +class EcTemplate < ActiveRecord::Base + # attr_accessible :title, :body + # acts_as_attachable + has_many :attachments, as: :container + +end diff --git a/app/models/exercise_answer_comment.rb b/app/models/exercise_answer_comment.rb index 7da0ec4c7..4279ba445 100644 --- a/app/models/exercise_answer_comment.rb +++ b/app/models/exercise_answer_comment.rb @@ -3,7 +3,7 @@ class ExerciseAnswerComment < ApplicationRecord belongs_to :user belongs_to :exercise_question belongs_to :exercise_shixun_answer, optional: true - belongs_to :exercise_answer,optional: true + belongs_to :exercise_answer, optional: true scope :search_answer_comments, lambda {|name,ids| where("#{name}":ids)} end diff --git a/app/models/graduation_task.rb b/app/models/graduation_task.rb index 4150c52bc..c42c92890 100644 --- a/app/models/graduation_task.rb +++ b/app/models/graduation_task.rb @@ -44,7 +44,7 @@ class GraduationTask < ApplicationRecord def user_work user_id - work = self.graduation_works.find_by(user_id: user_id) + work = self.graduation_works.find_by(user_id: user_id) || GraduationWork.create!(graduation_task_id: id, user_id: user_id) end def task_type_name diff --git a/app/models/gtopic_bank.rb b/app/models/gtopic_bank.rb index af5b267a6..609219711 100644 --- a/app/models/gtopic_bank.rb +++ b/app/models/gtopic_bank.rb @@ -1,7 +1,7 @@ class GtopicBank < ApplicationRecord belongs_to :user - belongs_to :graduation_topic - belongs_to :course_list + belongs_to :graduation_topic, optional: true + belongs_to :course_list, optional: true has_many :attachments, as: :container, dependent: :destroy has_many :graduation_topics, dependent: :nullify diff --git a/app/models/help.rb b/app/models/help.rb new file mode 100644 index 000000000..2b8bf5813 --- /dev/null +++ b/app/models/help.rb @@ -0,0 +1,3 @@ +class Help < ApplicationRecord + +end \ No newline at end of file diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb index c33bbca0d..4c8f94a42 100644 --- a/app/models/homework_common.rb +++ b/app/models/homework_common.rb @@ -102,7 +102,7 @@ class HomeworkCommon < ApplicationRecord end def user_work user_id - work = self.student_works.find_by_user_id(user_id) + work = self.student_works.find_by_user_id(user_id) || StudentWork.create!(homework_common_id: id, user_id: user_id) end # 是否在补交阶段内 diff --git a/app/models/school.rb b/app/models/school.rb index 1034fd997..24de02496 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -16,6 +16,8 @@ class School < ApplicationRecord has_many :customers, dependent: :destroy has_many :partners, dependent: :destroy + has_many :apply_add_departments, dependent: :destroy + # 学校管理员 def manager?(user) ec_school_users.exists?(user_id: user.id) diff --git a/app/models/searchable/course.rb b/app/models/searchable/course.rb index 5060d9ddd..794dec0e2 100644 --- a/app/models/searchable/course.rb +++ b/app/models/searchable/course.rb @@ -24,7 +24,7 @@ module Searchable::Course author_name: teacher&.real_name, author_school_name: teacher&.school_name, visits_count: visits, - members_count: members_count, + members_count: course_members_count, is_public: is_public == 1, first_category_url: ApplicationController.helpers.module_url(none_hidden_course_modules.first, self) } diff --git a/app/models/searchable/shixun.rb b/app/models/searchable/shixun.rb index 49e066eac..41bc94b04 100644 --- a/app/models/searchable/shixun.rb +++ b/app/models/searchable/shixun.rb @@ -14,7 +14,9 @@ module Searchable::Shixun def search_data { name: name, - description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH] + description: Util.extract_content(description)[0..Searchable::MAXIMUM_LENGTH], + status: status, + myshixuns_count: myshixuns_count }.merge!(searchable_user_data) .merge!(searchable_challenge_data) end @@ -37,7 +39,7 @@ module Searchable::Shixun end def should_index? - status == 2 # published + [0, 1, 2].include?(status) # published end def to_searchable_json @@ -48,13 +50,13 @@ module Searchable::Shixun author_school_name: user.school_name, visits_count: visits, challenges_count: challenges_count, - study_count: myshixuns_count + study_count: myshixuns_count, } end module ClassMethods def searchable_includes - { user: { user_extension: :school } } + [ :shixun_info, user: { user_extension: :school } ] end end end diff --git a/app/models/shixun.rb b/app/models/shixun.rb index 33d36d026..4912ea15a 100644 --- a/app/models/shixun.rb +++ b/app/models/shixun.rb @@ -5,6 +5,9 @@ class Shixun < ApplicationRecord # hide_code: 隐藏代码窗口 # code_hidden: 隐藏代码目录 # task_pass: 跳关 + # webssh 0:不开启webssh;1:开启练习模式; 2:开启评测模式 + # trainee 实训的难度 + # vnc: VCN实训是否用于评测 has_many :challenges, -> {order("challenges.position asc")}, dependent: :destroy has_many :challenge_tags, through: :challenges has_many :myshixuns, :dependent => :destroy @@ -35,6 +38,9 @@ class Shixun < ApplicationRecord has_one :shixun_info, dependent: :destroy + # 第二版本库 + has_one :shixun_secret_repository, dependent: :destroy + belongs_to :user # 实训服务配置 has_many :shixun_service_configs, :dependent => :destroy @@ -274,6 +280,11 @@ class Shixun < ApplicationRecord self.mirror_name.include?('JavaWeb') || self.mirror_name.include?('PHP') && self.mirror_name.include?('Mysql') || self.mirror_name.include?('Web') end + # 所属实践课程 + def relation_path + subjects.where(hidden: 0).uniq + end + private def send_tiding diff --git a/app/models/shixun_secret_repository.rb b/app/models/shixun_secret_repository.rb new file mode 100644 index 000000000..699c6dd30 --- /dev/null +++ b/app/models/shixun_secret_repository.rb @@ -0,0 +1,11 @@ +class ShixunSecretRepository < ApplicationRecord + # repo_name: 仓库名 + # secret_dir_name: 在tpm仓库的那个目录下 + + belongs_to :shixun + + def repo_path + "#{repo_name}.git" + end + +end diff --git a/app/models/shixun_work_comment.rb b/app/models/shixun_work_comment.rb new file mode 100644 index 000000000..7a67238ab --- /dev/null +++ b/app/models/shixun_work_comment.rb @@ -0,0 +1,5 @@ +class ShixunWorkComment < ApplicationRecord + belongs_to :student_work + belongs_to :user + belongs_to :challenge, optional: true +end diff --git a/app/models/student_work.rb b/app/models/student_work.rb index 26409da59..6b4025885 100644 --- a/app/models/student_work.rb +++ b/app/models/student_work.rb @@ -7,6 +7,7 @@ class StudentWork < ApplicationRecord belongs_to :myshixun, optional: true has_many :student_works_evaluation_distributions, dependent: :destroy has_many :student_works_scores, dependent: :destroy + has_many :shixun_work_comments, dependent: :destroy belongs_to :project, optional: true # attachtype: 1(正常提交的附件), 7(补交的附件) diff --git a/app/models/student_works_score.rb b/app/models/student_works_score.rb index 19043f7f8..86d393f93 100644 --- a/app/models/student_works_score.rb +++ b/app/models/student_works_score.rb @@ -9,6 +9,9 @@ belongs_to :student_work validates :comment, length: { maximum: 2000 } + scope :shixun_comment, lambda { where(is_ultimate: 0) } + + def show_name identity, user identity < Course::STUDENT || self.user == user || self.reviewer_role != 3 end diff --git a/app/models/subject.rb b/app/models/subject.rb index 4b7f4dbcd..d5ea3f433 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -46,8 +46,7 @@ class Subject < ApplicationRecord # 挑战过路径的成员数(金课统计去重后的报名人数) def member_count - excellent && CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).uniq.length > shixuns.pluck(:myshixuns_count).sum ? - CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).uniq.length : shixuns.pluck(:myshixuns_count).sum + excellent ? CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum end def all_score diff --git a/app/models/test_set.rb b/app/models/test_set.rb index 148cb8720..7772a3a00 100644 --- a/app/models/test_set.rb +++ b/app/models/test_set.rb @@ -1,2 +1,3 @@ class TestSet < ApplicationRecord + # match_rule: 匹配规则: full: 完全匹配, last: 末尾匹配 end diff --git a/app/models/tiding.rb b/app/models/tiding.rb index d885f93fd..02692085a 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -22,4 +22,9 @@ class Tiding < ApplicationRecord value end + + def anonymous? + (container_type == 'StudentWorksScore' && extra.to_i == 3) || + (container_type == 'StudentWorksScoresAppeal' && parent_container_type == 'StudentWork' && tiding_type == 'System') + end end \ No newline at end of file diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 5a0dc8a37..98afcb165 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -1,6 +1,6 @@ class UserExtension < ApplicationRecord # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 - enum identity: { teacher: 0, student: 1, professional: 2, developer: 3 } + enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, cnmooc: 4, unselect: -1 } belongs_to :user, touch: true belongs_to :school, optional: true diff --git a/app/queries/admins/unit_apply_query.rb b/app/queries/admins/unit_apply_query.rb new file mode 100644 index 000000000..5df9c8ebb --- /dev/null +++ b/app/queries/admins/unit_apply_query.rb @@ -0,0 +1,24 @@ +class Admins::UnitApplyQuery < ApplicationQuery + include CustomSortable + + attr_reader :params + + sort_columns :created_at, default_by: :created_at, default_direction: :desc + + def initialize(params) + @params = params + end + + def call + unit_applies = ApplyAddSchool.where(status:0) + + # 关键字模糊查询 + keyword = params[:keyword].to_s.strip + if keyword.present? + unit_applies = unit_applies.where("name like ?","%#{keyword}%") + end + + custom_sort(unit_applies, params[:sort_by], params[:sort_direction]) + end +end + diff --git a/app/services/admins/delete_unit_apply_service.rb b/app/services/admins/delete_unit_apply_service.rb new file mode 100644 index 000000000..a64c8d64d --- /dev/null +++ b/app/services/admins/delete_unit_apply_service.rb @@ -0,0 +1,56 @@ +class Admins::DeleteUnitApplyService < ApplicationService + + attr_reader :department, :params + + def initialize(unit_apply, params) + @unit_apply = unit_apply + @params = params + end + + def call + ActiveRecord::Base.transaction do + @unit_apply.update_attribute("status",3) + @unit_apply&.applied_messages&.update_all(status:3) + @unit_apply&.school&.apply_add_departments&.update_all(status:3) + + applied_departments = ApplyAddDepartment.where(school_id: @unit_apply.school_id) + applied_departments.update_all(status: 3) + + use_extensions = UserExtension&.where(school_id: @unit_apply.school_id) + user_ids = UserExtension&.where(school_id: @unit_apply.school_id)&.pluck(:user_id) + User.where(id: user_ids).update_all(profile_completed: false) + use_extensions.update_all(school_id: nil,department_id: nil) + + @unit_apply&.user&.user_extension&.update_attribute("department_id", nil) + + # 申请了职业认证的用户撤销申请 + apply_user_auth = ApplyUserAuthentication.where(user_id: user_ids, auth_type: 2, status: 0) + apply_user_auth.each do |apply| + apply.tidings.destroy_all + apply.update_attribute('status', 3) + diskfile2 = disk_auth_filename('UserAuthentication', apply.user_id, 'PRO') + diskfilePRO = diskfile2 + 'temp' + File.delete(diskfilePRO) if File.exist?(diskfilePRO) + File.delete(diskfile2) if File.exist?(diskfile2) + end + + # 未审批删除 + if params[:tip] == "unapplied" + Tiding.where(:user_id => 1, :trigger_user_id => @unit_apply.user_id, :container_id => @unit_apply.id, :container_type => 'ApplyAddSchools', :status => 0, :tiding_type => "Apply").update_all(status: 1) + Tiding.create(:user_id => @unit_apply.user_id, :trigger_user_id => 0, :container_id => @unit_apply.id, :container_type =>'ApplyAddSchools', :belong_container_id => @unit_apply.school_id, :belong_container_type=> 'School', :tiding_type => "System", :status => 2, :extra => params[:reason]) + + Tiding.where(:user_id => 1, :container_id => applied_departments.pluck(:id), :container_type => 'ApplyAddDepartment', :status => 0, :tiding_type => "Apply").update_all(status: 1) + if applied_departments&.first.present? + Tiding.create(:user_id => applied_departments.first.user_id, :trigger_user_id => 0, :container_id => applied_departments.first.id, :container_type =>'ApplyAddDepartment', :belong_container_id => @unit_apply.school_id, :belong_container_type=> 'School', :tiding_type => "System", :status => 2) + AppliedMessage.create(:user_id => applied_departments.first.user_id, :status => 3, :viewed => 0, :applied_id => applied_departments.first.id, :applied_type => "ApplyAddDepartment", :name => applied_departments.first.name ) + end + @unit_apply&.school&.destroy + @unit_apply&.school&.departments&.destroy_all + elsif params[:tip] == "applied" + applied_departments.destroy_all + @unit_apply.destroy + end + end + + end +end \ No newline at end of file diff --git a/app/services/admins/drag_cooperative_service.rb b/app/services/admins/drag_cooperative_service.rb new file mode 100644 index 000000000..241b7eb11 --- /dev/null +++ b/app/services/admins/drag_cooperative_service.rb @@ -0,0 +1,35 @@ +class Admins::DragCooperativeService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :move, :after + + def initialize(move, after) + @move = move + @after = after # 移动后下一个位置的元素 + end + + def call + return if move.position + 1 == after&.position # 未移动 + raise Error, '未知错误' if after && move.img_type != after.img_type + + coo_imgs = CooImg.where(img_type: move.img_type) + + ActiveRecord::Base.transaction do + if after.blank? # 移动至末尾 + total = coo_imgs.count + + coo_imgs.where('position > ?', move.position).update_all('position = position - 1') + move.update!(position: total) + return + end + + if move.position > after.position # 前移 + coo_imgs.where('position >= ? AND position < ?', after.position, move.position).update_all('position = position + 1') + move.update!(position: after.position) + else # 后移 + coo_imgs.where('position > ? AND position <= ?', move.position, after.position).update_all('position = position - 1') + move.update!(position: after.position) + end + end + end +end \ No newline at end of file diff --git a/app/services/admins/update_user_service.rb b/app/services/admins/update_user_service.rb index 9531d3718..c4755a1ae 100644 --- a/app/services/admins/update_user_service.rb +++ b/app/services/admins/update_user_service.rb @@ -11,7 +11,7 @@ class Admins::UpdateUserService < ApplicationService def call user.assign_attributes(user_attributes) user.firstname = '' - user.password = password if params[:password].present? + user.password = params[:password] if params[:password].present? if params[:identity].to_s == 'student' params[:technical_title] = nil diff --git a/app/services/concerns/elasticsearch_able.rb b/app/services/concerns/elasticsearch_able.rb index 80ca5467e..015aac29b 100644 --- a/app/services/concerns/elasticsearch_able.rb +++ b/app/services/concerns/elasticsearch_able.rb @@ -28,9 +28,11 @@ module ElasticsearchAble end def body_options - { - min_score: EduSetting.get('es_min_score') || 10 - } + hash = {} + + hash[:min_score] = (EduSetting.get('es_min_score') || 10) if keyword != '*' + + hash end def per_page diff --git a/app/services/libraries/agree_apply_service.rb b/app/services/libraries/agree_apply_service.rb index d452083b3..3367e4585 100644 --- a/app/services/libraries/agree_apply_service.rb +++ b/app/services/libraries/agree_apply_service.rb @@ -25,7 +25,7 @@ class Libraries::AgreeApplyService < ApplicationService private def notify_library_author! - Tiding.create!(user_id: library.user_id, trigger_user_id: 1, + Tiding.create!(user_id: library.user_id, trigger_user_id: 0, container_id: library.id, container_type: 'Library', tiding_type: 'System', status: 1) end diff --git a/app/services/libraries/refuse_apply_service.rb b/app/services/libraries/refuse_apply_service.rb index 9b249b6fa..9868c5989 100644 --- a/app/services/libraries/refuse_apply_service.rb +++ b/app/services/libraries/refuse_apply_service.rb @@ -32,7 +32,7 @@ class Libraries::RefuseApplyService < ApplicationService private def notify_library_author! - Tiding.create!(user_id: library.user_id, trigger_user_id: 1, + Tiding.create!(user_id: library.user_id, trigger_user_id: 0, container_id: library.id, container_type: 'Library', tiding_type: 'System', status: 2, extra: library_apply.reason) end diff --git a/app/services/project_packages/agree_apply_service.rb b/app/services/project_packages/agree_apply_service.rb index 7cef7f70c..3361babad 100644 --- a/app/services/project_packages/agree_apply_service.rb +++ b/app/services/project_packages/agree_apply_service.rb @@ -29,7 +29,7 @@ class ProjectPackages::AgreeApplyService < ApplicationService Tiding.where(container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Apply', status: 0).update_all(status: 1) - Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + Tiding.create!(user_id: package.creator_id, trigger_user_id: 0, container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'System', status: 1) end diff --git a/app/services/project_packages/end_bidding_service.rb b/app/services/project_packages/end_bidding_service.rb index 6d43db949..c0d5b76da 100644 --- a/app/services/project_packages/end_bidding_service.rb +++ b/app/services/project_packages/end_bidding_service.rb @@ -16,7 +16,7 @@ class ProjectPackages::EndBiddingService < ApplicationService private def send_bidding_end_notify! - Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + Tiding.create!(user_id: package.creator_id, trigger_user_id: 0, container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'BiddingEnd') end diff --git a/app/services/project_packages/refuse_apply_service.rb b/app/services/project_packages/refuse_apply_service.rb index 142efe1e0..972a7004f 100644 --- a/app/services/project_packages/refuse_apply_service.rb +++ b/app/services/project_packages/refuse_apply_service.rb @@ -31,7 +31,7 @@ class ProjectPackages::RefuseApplyService < ApplicationService Tiding.where(container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Apply', status: 0).update_all(status: 1) - Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + Tiding.create!(user_id: package.creator_id, trigger_user_id: 0, container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'System', status: 2, extra: apply.reason) end diff --git a/app/services/project_packages/save_service.rb b/app/services/project_packages/save_service.rb index 8385ac5dd..40d33c453 100644 --- a/app/services/project_packages/save_service.rb +++ b/app/services/project_packages/save_service.rb @@ -71,7 +71,7 @@ class ProjectPackages::SaveService < ApplicationService end def send_create_notify! - Tiding.create!(user_id: package.creator_id, trigger_user_id: 1, + Tiding.create!(user_id: package.creator_id, trigger_user_id: 0, container_id: package.id, container_type: 'ProjectPackage', tiding_type: 'Created') end diff --git a/app/services/search_service.rb b/app/services/search_service.rb index 7cd1857bd..418021cc0 100644 --- a/app/services/search_service.rb +++ b/app/services/search_service.rb @@ -14,10 +14,12 @@ class SearchService < ApplicationService private def search_options - { + model_options = { index_name: index_names, model_includes: model_includes - }.merge(default_options) + } + model_options.merge(where: { status: 2 }) if index_names == [Shixun] + model_options.merge(default_options) end def index_names diff --git a/app/services/shixun_search_service.rb b/app/services/shixun_search_service.rb new file mode 100644 index 000000000..911f341f8 --- /dev/null +++ b/app/services/shixun_search_service.rb @@ -0,0 +1,56 @@ +class ShixunSearchService < ApplicationService + include ElasticsearchAble + + attr_reader :params + + def initialize(params) + @params = params + end + + def call + # 全部实训/我的实训 + type = params[:type] || "all" + # 状态:已发布/未发布 + status = params[:status] || "all" + + # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) + if type == "mine" + @shixuns = User.current.shixuns.none_closed + else + if User.current.admin? || User.current.business? + @shixuns = Shixun.none_closed.where(hidden: 0) + else + none_shixun_ids = ShixunSchool.where("school_id != #{User.current.school_id}").pluck(:shixun_id) + + @shixuns = Shixun.where.not(id: none_shixun_ids).none_closed.where(hidden: 0) + end + end + + unless status == "all" + @shixuns = status == "published" ? @shixuns.where(status: 2) : @shixuns.where(status: [0, 1]) + end + + ## 筛选 难度 + if params[:diff].present? && params[:diff].to_i != 0 + @shixuns = @shixuns.where(trainee: params[:diff]) + end + + Shixun.search(keyword, search_options) + end + + private + + def search_options + model_options = { + 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!(default_options) + model_options + end + + def sort_str + params[:order] || "desc" + end +end \ No newline at end of file diff --git a/app/services/users/apply_professional_auth_service.rb b/app/services/users/apply_professional_auth_service.rb index 07afe18ae..3ba9fbafd 100644 --- a/app/services/users/apply_professional_auth_service.rb +++ b/app/services/users/apply_professional_auth_service.rb @@ -38,7 +38,11 @@ class Users::ApplyProfessionalAuthService < ApplicationService move_image_file! unless params[:upload_image].to_s == 'false' - sms_notify_admin + # sms_cache = Rails.cache.read("apply_pro_certification") + # if sms_cache.nil? + # sms_notify_admin + Rails.cache.write("apply_pro_certification", 1) + # end end end diff --git a/app/services/users/course_service.rb b/app/services/users/course_service.rb index de70c5b86..db9be69bc 100644 --- a/app/services/users/course_service.rb +++ b/app/services/users/course_service.rb @@ -11,7 +11,7 @@ class Users::CourseService end def call - courses = category_scope_courses.not_deleted + courses = category_scope_courses.not_deleted.not_excellent courses = status_filter(courses) diff --git a/app/services/users/question_bank_service.rb b/app/services/users/question_bank_service.rb index 7e640c6a5..dbaa92e6e 100644 --- a/app/services/users/question_bank_service.rb +++ b/app/services/users/question_bank_service.rb @@ -85,7 +85,7 @@ class Users::QuestionBankService def custom_sort(relations, sort_by, sort_direction) case sort_by when 'updated_at' then - relations.order(updated_at: sort_direction) + relations.order("updated_at #{sort_direction}, id #{sort_direction}") when 'name' then relations.order("CONVERT(name USING gbk) COLLATE gbk_chinese_ci #{sort_direction}") when 'contributor' then diff --git a/app/services/users/update_account_service.rb b/app/services/users/update_account_service.rb index 3f0aa8cc8..fad1210a5 100644 --- a/app/services/users/update_account_service.rb +++ b/app/services/users/update_account_service.rb @@ -53,7 +53,7 @@ class Users::UpdateAccountService < ApplicationService RewardGradeService.call(user, container_id: user.id, container_type: 'Account', score: 500) if user.user_extension.teacher? join_course(user.id,1309, 2) - sms_notify_admin(user.lastname) + # sms_notify_admin(user.lastname) end end diff --git a/app/services/videos/agree_apply_service.rb b/app/services/videos/agree_apply_service.rb index 50791935a..0a95961ab 100644 --- a/app/services/videos/agree_apply_service.rb +++ b/app/services/videos/agree_apply_service.rb @@ -28,7 +28,7 @@ class Videos::AgreeApplyService < ApplicationService private def notify_video_author! - Tiding.create!(user_id: video.user_id, trigger_user_id: 1, + Tiding.create!(user_id: video.user_id, trigger_user_id: 0, container_id: video.id, container_type: 'Video', tiding_type: 'System', status: 1) end diff --git a/app/services/videos/refuse_apply_service.rb b/app/services/videos/refuse_apply_service.rb index 5d796db79..5a2cc4ef9 100644 --- a/app/services/videos/refuse_apply_service.rb +++ b/app/services/videos/refuse_apply_service.rb @@ -31,7 +31,7 @@ class Videos::RefuseApplyService < ApplicationService private def notify_video_author! - Tiding.create!(user_id: video.user_id, trigger_user_id: 1, + Tiding.create!(user_id: video.user_id, trigger_user_id: 0, container_id: video.id, container_type: 'Video', tiding_type: 'System', status: 2, extra: video_apply.reason) end diff --git a/app/templates/shared/main.css b/app/templates/shared/main.css index 884f6fa37..31ebfabac 100644 --- a/app/templates/shared/main.css +++ b/app/templates/shared/main.css @@ -83,6 +83,7 @@ a.edu-txt-w80,.edu-txt-w80{ width:80px; display: inline-block;text-align: center .font-20{ font-size: 20px!important;} .font-22{ font-size: 22px!important;} .font-24{ font-size: 24px!important;} +.font-25{ font-size: 25px!important;} .font-26{ font-size: 26px!important;} .font-28{ font-size: 28px!important;} .font-30{ font-size: 30px!important;} @@ -105,7 +106,7 @@ a.decoration{text-decoration: underline} .mr3{margin-right: 3px}.mr4{margin-right: 4px}.mr5{ margin-right: 5px;}.mr8{ margin-right: 8px;}.mr10{ margin-right: 10px;}.mr12{ margin-right:12px!important;}.mr15{ margin-right: 15px;}.mr18{ margin-right: 18px;}.mr20{ margin-right: 20px;}.mr24{ margin-right: 24px;}.mr25{ margin-right: 25px;}.mr30{ margin-right:30px;}.mr35{margin-right:35px;}.mr40{margin-right:40px;}.mr45{margin-right:45px;}.mr50{ margin-right: 50px;}.mr60{ margin-right:60px;}.mr70{ margin-right: 70px;}.mr75{ margin-right: 75px;}.mr80{ margin-right:80px;}.mr90{ margin-right:90px;}.mr100{ margin-right: 100px;}.mr110{ margin-right:110px;}.mr350{ margin-right:350px;} .pt1{ padding-top:1px;}.pt3{ padding-top:3px!important;}.pt5{ padding-top:5px!important;}.pt10{ padding-top:10px;}.pt15{ padding-top:15px;}.pt17{ padding-top:17px;}.pt20{ padding-top:20px!important;}.pt25{ padding-top:25px;}.pt30{ padding-top:30px;}.pt35{ padding-top:35px;}.pt37{ padding-top:37px;}.pt40{ padding-top:40px;}.pt47{ padding-top:47px;}.pt49{ padding-top:49px;}.pt50{ padding-top:50px;}.pt60{ padding-top:60px;}.pt70{ padding-top:70px;}.pt80{ padding-top:80px;}.pt90{ padding-top:90px;}.pt100{padding-top:100px;}.pt110{ padding-top:110px;}.pt120{ padding-top:120px;}.pt130{padding-top:130px;} -.pb3{ padding-bottom:3px!important;}.pb5{ padding-bottom:5px!important;}.pb10{ padding-bottom:10px;}.pb15{ padding-bottom:15px;}.pb20{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb30{ padding-bottom:30px;}.pb35{ padding-bottom:35px;}.pb40{ padding-bottom:40px;}.pb47{ padding-bottom:47px;}.pb50{ padding-bottom:50px;}.pb60{ padding-bottom:60px;}.pb70{ padding-bottom:70px;}.pb80{ padding-bottom:80px;}.pb90{ padding-bottom:90px;}.pb100{ padding-bottom:100px;}.pb110{ padding-bottom:110px;}.pb155{ padding-bottom:155px;} +.pb3{ padding-bottom:3px!important;}.pb5{ padding-bottom:5px!important;}.pb10{ padding-bottom:10px;}.pb15{ padding-bottom:15px;}.pb20{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb25{ padding-bottom:20px;}.pb28{ padding-bottom:28px;}.pb30{ padding-bottom:30px;}.pb35{ padding-bottom:35px;}.pb40{ padding-bottom:40px;}.pb47{ padding-bottom:47px;}.pb50{ padding-bottom:50px;}.pb60{ padding-bottom:60px;}.pb70{ padding-bottom:70px;}.pb80{ padding-bottom:80px;}.pb90{ padding-bottom:90px;}.pb100{ padding-bottom:100px;}.pb110{ padding-bottom:110px;}.pb155{ padding-bottom:155px;} .pr2{ paddding-right:2px;}.pr5{ padding-right:5px;}.pr10{ padding-right:10px;}.pr15{ padding-right:15px;}.pr20{ padding-right:20px!important;}.pr30{ padding-right:30px!important;}.pr35{ padding-right:35px!important;}.pr42{ padding-right:42px;}.pr45{ padding-right:45px;}.pr48{ padding-right:48px;}.pr57{ padding-right:57px;}.pr60{ padding-right:60px;}.pr70{ padding-right:70px;}.pr72{ padding-right:72px;}.pr75{ padding-right:75px;}.pr88{ padding-right:88px;} .pl0{ padding-left:0px!important;}.pl2{ padding-left:2px;}.pl5{ padding-left:5px;}.pl7{ padding-left:7px;}.pl8{ padding-left:8px;}.pl10{ padding-left:10px;}.pl15{ padding-left:15px;}.pl20{ padding-left:20px;}.pl22{ padding-left:22px;}.pl25{ padding-left:25px;}.pl28{ padding-left:28px;}.pl30{ padding-left:30px !important;}.pl33{padding-left: 33px}.pl35{ padding-left:35px;}.pl40{ padding-left:40px;}.pl42{ padding-left:42px;}.pl45{ padding-left:45px;}.pl50{ padding-left:50px;}.pl60{ padding-left:60px;}.pl70{padding-left:70px;}.pl75{padding-left:75px;}.pl80{padding-left:80px;}.pl88{ padding-left:88px;}.pl92{padding-left:92px;}.pl100{ padding-left:100px;} @@ -556,11 +557,6 @@ a.user_greybg_btn{background-color:#747A7F;color: #fff;} .cdefault{cursor: default} -/*md编辑器恢复被覆盖样式*/ -.new_li li{ list-style-type: disc!important; } -.new_li ol li{ list-style-type: decimal!important; } -.new_li li{ margin-bottom: 0!important; } - /*搜索框*/ #pollingPanel{position: relative;width: 248px;height: 32px;} #pollingPanel > input{width: 100%;height: 100%;border:1px solid #eaeaea;border-radius: 4px;padding: 0px 30px 0px 5px;box-sizing: border-box;background-color: #F4F4F4;} diff --git a/app/views/admins/abouts/edit.html.erb b/app/views/admins/abouts/edit.html.erb new file mode 100644 index 000000000..4e75940c2 --- /dev/null +++ b/app/views/admins/abouts/edit.html.erb @@ -0,0 +1,15 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('关于我们') %> +<% end %> + +
+ <%= simple_form_for(@doc, url: admins_about_path) do |f| %> +
+ <%= text_area_tag('about_us', @doc.about_us, style: 'display: none') %> +
+ +
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admins/agreements/edit.html.erb b/app/views/admins/agreements/edit.html.erb new file mode 100644 index 000000000..b5de7c1fc --- /dev/null +++ b/app/views/admins/agreements/edit.html.erb @@ -0,0 +1,15 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('服务协议') %> +<% end %> + +
+ <%= simple_form_for(@doc, url: admins_agreement_path) do |f| %> +
+ <%= text_area_tag('agreement', @doc.agreement, style: 'display: none') %> +
+ +
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admins/auth_schools/add_manager.js.erb b/app/views/admins/auth_schools/add_manager.js.erb new file mode 100644 index 000000000..e5992f9b3 --- /dev/null +++ b/app/views/admins/auth_schools/add_manager.js.erb @@ -0,0 +1,8 @@ +if($(".auth-schools-user-add").length > 0){ + $(".auth-schools-user-add").modal("hide") +} +<% if @school_users.size > 0 %> + $("#table-school-<%= @school_id %>").find(".school_user_list").html("<%= j render partial: "admins/auth_schools/shared/school_user_list", locals: {users: @school_users, school_id: @school_id} %> ") +<% end %> + +show_success_flash() \ No newline at end of file diff --git a/app/views/admins/auth_schools/add_school.js.erb b/app/views/admins/auth_schools/add_school.js.erb new file mode 100644 index 000000000..1c7db0ace --- /dev/null +++ b/app/views/admins/auth_schools/add_school.js.erb @@ -0,0 +1,4 @@ +$(".auth-schools-list-container").html("<%= j render partial: "admins/auth_schools/shared/list", locals: {schools: @schools} %>") +$(".auth-schools-new-add").modal("hide") + +show_success_flash() \ No newline at end of file diff --git a/app/views/admins/auth_schools/index.html.erb b/app/views/admins/auth_schools/index.html.erb new file mode 100644 index 000000000..5f0f5e46b --- /dev/null +++ b/app/views/admins/auth_schools/index.html.erb @@ -0,0 +1,14 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('认证单位列表') %> +<% end %> + +
+ <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.auth-schools-new-add' } %> +
+ +
+ <%= render(partial: 'admins/auth_schools/shared/list', locals: { schools: @schools }) %> +
+ +<%= render partial: "admins/auth_schools/shared/new_modal" %> +<%= render partial: "admins/auth_schools/shared/user_add_modal" %> \ No newline at end of file diff --git a/app/views/admins/auth_schools/index.js.erb b/app/views/admins/auth_schools/index.js.erb new file mode 100644 index 000000000..d96cad477 --- /dev/null +++ b/app/views/admins/auth_schools/index.js.erb @@ -0,0 +1 @@ +$(".auth-schools-list-container").html("<%= j render partial: "admins/auth_schools/shared/list", locals: {schools: @schools} %>") \ No newline at end of file diff --git a/app/views/admins/auth_schools/remove_manager.js.erb b/app/views/admins/auth_schools/remove_manager.js.erb new file mode 100644 index 000000000..b9a5761aa --- /dev/null +++ b/app/views/admins/auth_schools/remove_manager.js.erb @@ -0,0 +1,3 @@ + +$("#table-school-<%= params[:school_id] %>").find("#manager-<%= params[:user_id] %>").remove() +show_success_flash() \ No newline at end of file diff --git a/app/views/admins/auth_schools/search_manager.js.erb b/app/views/admins/auth_schools/search_manager.js.erb new file mode 100644 index 000000000..9a37394d5 --- /dev/null +++ b/app/views/admins/auth_schools/search_manager.js.erb @@ -0,0 +1,4 @@ + +if($("#add-users-list").length > 0){ + $("#add-users-list").html("<%= j render partial: "admins/auth_schools/shared/add_users_list", locals: {users: @users, school_id: params[:school_id]} %>") +} \ No newline at end of file diff --git a/app/views/admins/auth_schools/search_school.js.erb b/app/views/admins/auth_schools/search_school.js.erb new file mode 100644 index 000000000..bc42e27b5 --- /dev/null +++ b/app/views/admins/auth_schools/search_school.js.erb @@ -0,0 +1,3 @@ +if($("#add-schools-list").length > 0){ + $("#add-schools-list").html("<%= j render partial: "admins/auth_schools/shared/add_schools_list", locals: {schools: @schools} %>") +} \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_add_schools_list.html.erb b/app/views/admins/auth_schools/shared/_add_schools_list.html.erb new file mode 100644 index 000000000..7db127efd --- /dev/null +++ b/app/views/admins/auth_schools/shared/_add_schools_list.html.erb @@ -0,0 +1,23 @@ + +<%= form_tag(add_school_admins_auth_schools_path, method: :post, remote: true) do %> +
+
单位名称
+
+ <% if schools.size > 0 %> + <% schools.each do |school| %> +
+ <%= check_box_tag("school_id[]", school.id, false, id: "check_school_#{school.id}") %> + +
+ <% end %> + <% else %> +

没有相关的单位

+ <% end %> +
+
+
+ <%= submit_tag("确认",class: "btn btn-primary submit-btn") %> +
+<% end %> \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_add_users_list.html.erb b/app/views/admins/auth_schools/shared/_add_users_list.html.erb new file mode 100644 index 000000000..25bb4e85d --- /dev/null +++ b/app/views/admins/auth_schools/shared/_add_users_list.html.erb @@ -0,0 +1,31 @@ +<%= form_tag(add_manager_admins_auth_schools_path, method: :post, remote: true) do %> + <%= hidden_field_tag("school_id",school_id) %> +
+
+ 姓名 + 单位 +
+
+ <% if users.size > 0 %> + <% users.each do |user| %> +
+ <%= check_box_tag("user_id[]", user.id, false, id: "check_user_#{user.id}") %> + +
+ <% end %> + <% else %> +

没有相关的单位

+ <% end %> +
+
+
+ <%= submit_tag("确认",class: "btn btn-primary submit-btn") %> +
+<% end %> \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_list.html.erb b/app/views/admins/auth_schools/shared/_list.html.erb new file mode 100644 index 000000000..d56f6a732 --- /dev/null +++ b/app/views/admins/auth_schools/shared/_list.html.erb @@ -0,0 +1,38 @@ + + + + + + + + + + <% if schools.size > 0 %> + <% schools.each_with_index do |school, index| %> + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号学校名称学校管理员操作
<%= list_index_no(@params_page.to_i, index) %> + <%= link_to "#{school.name}", "/ecs/department?school_id=#{school.id}", target: "_blank" %> + +
+ <%= link_to "".html_safe, "javascript:void(0)", class: "action", onclick: "show_add_manager('#{school.id}')" %> +
+
+ <% if school.users.size > 0 %> + <%= render partial: "admins/auth_schools/shared/school_user_list", locals: {users: school.users, school_id: school.id} %> + <% end %> +
+
+ <%= link_to "".html_safe, admins_auth_school_path(school), method: :delete, data: {confirm: "确认删除吗?"}, remote: true %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %> \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_new_modal.html.erb b/app/views/admins/auth_schools/shared/_new_modal.html.erb new file mode 100644 index 000000000..3bec99303 --- /dev/null +++ b/app/views/admins/auth_schools/shared/_new_modal.html.erb @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_school_user_list.html.erb b/app/views/admins/auth_schools/shared/_school_user_list.html.erb new file mode 100644 index 000000000..13e6ff905 --- /dev/null +++ b/app/views/admins/auth_schools/shared/_school_user_list.html.erb @@ -0,0 +1,6 @@ +<% users.each do |user| %> + + <%= link_to user.show_real_name, "/users/#{user.login}", target: "_blank" %> + <%= link_to "×", remove_manager_admins_auth_schools_path(user_id: user.id, school_id: school_id),method: :post, class: "font-16 ml3", remote: true %> + +<% end %> \ No newline at end of file diff --git a/app/views/admins/auth_schools/shared/_user_add_modal.html.erb b/app/views/admins/auth_schools/shared/_user_add_modal.html.erb new file mode 100644 index 000000000..39dd7d1b7 --- /dev/null +++ b/app/views/admins/auth_schools/shared/_user_add_modal.html.erb @@ -0,0 +1,36 @@ + \ No newline at end of file diff --git a/app/views/admins/contact_us/edit.html.erb b/app/views/admins/contact_us/edit.html.erb new file mode 100644 index 000000000..a0b085065 --- /dev/null +++ b/app/views/admins/contact_us/edit.html.erb @@ -0,0 +1,41 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('联系我们') + end +%> + +
+ <% @cooperations.each do |cooperation| %> +
+
+
<%= cooperation.user_type_text %>
+
+ <%= simple_form_for(cooperation, url: admins_contact_us_path(id: cooperation.id), wrapper: :horizontal_form) do |f| %> + <%= f.input :name, label: '联系人:' %> + <%= f.input :qq, label: 'QQ:' %> + <%= f.input :mail, label: 'Email:' %> + +
+ <%= f.button :submit, value: '保存', class: 'btn-primary btn-sm', 'data-disable-with': '保存中...' %> +
+ <% end %> +
+
+
+ <% end %> + +
+
+
公司地址
+
+ <%= simple_form_for(@help, url: update_address_admins_contact_us_path, wrapper: :horizontal_form) do |f| %> + <%= f.input :status, label: '地址:' %> + +
+ <%= f.button :submit, value: '保存', class: 'btn-primary btn-sm', 'data-disable-with': '保存中...' %> +
+ <% end %> +
+
+
+
\ No newline at end of file diff --git a/app/views/admins/cooperatives/index.html.erb b/app/views/admins/cooperatives/index.html.erb new file mode 100644 index 000000000..caf236c5c --- /dev/null +++ b/app/views/admins/cooperatives/index.html.erb @@ -0,0 +1,38 @@ +<% + define_admin_breadcrumbs do + add_admin_breadcrumb('合作伙伴') + end +%> + +<% @data.each do |type, objs| %> +
+
+ <%= t("enumerize.coo_img.img_type.#{type}") %> + <%= javascript_void_link '添加', class: 'btn btn-primary btn-sm add-btn', data: { img_type: type, toggle: 'modal', target: '.admin-add-cooperative-modal' } %> +
+
+ <% objs.sort_by(&:position).each do |obj| %> +
+
+ <%= delete_link '删除', admins_cooperative_path(obj, element: ".coo-img-item-#{obj.id}", not_refresh: true) do %> + + <% end %> + +
+ +
+
+ +
+ +
+
+
+
+ <% end %> +
+
+<% end %> + +<%= render partial: 'admins/cooperatives/shared/add_cooperative_modal' %> +<%= render partial: 'admins/shared/modal/upload_file_modal' %> \ No newline at end of file diff --git a/app/views/admins/cooperatives/shared/_add_cooperative_modal.html.erb b/app/views/admins/cooperatives/shared/_add_cooperative_modal.html.erb new file mode 100644 index 000000000..e5b6f0cea --- /dev/null +++ b/app/views/admins/cooperatives/shared/_add_cooperative_modal.html.erb @@ -0,0 +1,37 @@ + \ No newline at end of file diff --git a/app/views/admins/department_applies/agree.js.erb b/app/views/admins/department_applies/agree.js.erb deleted file mode 100644 index d6a9f078a..000000000 --- a/app/views/admins/department_applies/agree.js.erb +++ /dev/null @@ -1,2 +0,0 @@ -//$("#apply-id-<%= @depart_apply.id %>").remove() -//pop_box_new("批准成功", 400, 248); \ No newline at end of file diff --git a/app/views/admins/department_applies/index.html.erb b/app/views/admins/department_applies/index.html.erb index 72e0e42fc..49b38e31a 100644 --- a/app/views/admins/department_applies/index.html.erb +++ b/app/views/admins/department_applies/index.html.erb @@ -15,4 +15,4 @@ <%= render(partial: 'admins/shared/admin_common_refuse_modal') %> -<%= render partial: 'admins/department_applies/shared/edit_modal' %> \ No newline at end of file +<%= render 'admins/departments/shared/merge_department_modal' %> \ No newline at end of file diff --git a/app/views/admins/department_applies/shared/_edit_modal.html.erb b/app/views/admins/department_applies/shared/_edit_modal.html.erb deleted file mode 100644 index 44c38ac28..000000000 --- a/app/views/admins/department_applies/shared/_edit_modal.html.erb +++ /dev/null @@ -1,26 +0,0 @@ - \ No newline at end of file diff --git a/app/views/admins/department_applies/shared/_list.html.erb b/app/views/admins/department_applies/shared/_list.html.erb index a31e39a37..0a1d803be 100644 --- a/app/views/admins/department_applies/shared/_list.html.erb +++ b/app/views/admins/department_applies/shared/_list.html.erb @@ -1,12 +1,12 @@ - - - + + + - + @@ -14,26 +14,25 @@ <% applies.each do |apply| %> - - - + + + <% end %> <% else %> <%= render 'admins/shared/no_data_for_table' %> <% end %> -
ID部门名称单位名称ID部门名称单位名称 创建者 <%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %>操作操作
<%= apply.id %> <%= apply.name %> <%= apply.school.try(:name) %><%= apply.user.show_real_name %> <%= apply.name %> <%= apply.school.try(:name) %><%= apply&.user&.real_name %> <%= format_time apply.created_at %> <%= agree_link '批准', agree_admins_department_apply_path(apply, element: ".department-apply-#{apply.id}"), 'data-confirm': '确认批准通过?' %> <%= javascript_void_link('删除', class: 'action refuse-action', data: { toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id, title: "删除原因", type: "delete", - url: admins_department_apply_path(apply, element: ".department-apply-#{apply.id}") + url: admins_department_apply_path(apply,tip:"unapplied", element: ".department-apply-#{apply.id}") }) %> - - <%= javascript_void_link('修改', class: 'action department-apply-action', data: { toggle: 'modal', target: '.department-apply-edit-modal', id: apply.id }) %> + <%= javascript_void_link '更改', class: 'action', data: { school_id: apply.school_id, department_id: apply.id, + toggle: 'modal', target: '.admin-merge-department-modal', url: merge_admins_department_applies_path } %>
diff --git a/app/views/admins/departments/shared/_department_item.html.erb b/app/views/admins/departments/shared/_department_item.html.erb index 11584909d..64b4ee70b 100644 --- a/app/views/admins/departments/shared/_department_item.html.erb +++ b/app/views/admins/departments/shared/_department_item.html.erb @@ -28,7 +28,8 @@ <%= javascript_void_link '添加管理员', class: 'action', data: { department_id: department.id, toggle: 'modal', target: '.admin-add-department-member-modal' } %> - <%= javascript_void_link '更改', class: 'action', data: { school_id: department.school_id, department_id: department.id, toggle: 'modal', target: '.admin-merge-department-modal' } %> + <%= javascript_void_link '更改', class: 'action', data: { school_id: department.school_id, department_id: department.id, + toggle: 'modal', target: '.admin-merge-department-modal', url: merge_admins_departments_path } %> <%= delete_link '删除', admins_department_path(department, element: ".department-item-#{department.id}"), class: 'delete-department-action' %> \ No newline at end of file diff --git a/app/views/admins/departments/shared/_merge_department_modal.html.erb b/app/views/admins/departments/shared/_merge_department_modal.html.erb index 200e75ccd..5c1ca6892 100644 --- a/app/views/admins/departments/shared/_merge_department_modal.html.erb +++ b/app/views/admins/departments/shared/_merge_department_modal.html.erb @@ -18,7 +18,6 @@ -
diff --git a/app/views/admins/ec_templates/create_template.js.erb b/app/views/admins/ec_templates/create_template.js.erb new file mode 100644 index 000000000..fccd8cf20 --- /dev/null +++ b/app/views/admins/ec_templates/create_template.js.erb @@ -0,0 +1,3 @@ +$(".ec-templates-new-add").modal("hide") +$(".ec-templates-list-container").html("<%= j render partial: "admins/ec_templates/shared/list", locals: {templates: @templates} %>") +show_success_flash() \ No newline at end of file diff --git a/app/views/admins/ec_templates/index.html.erb b/app/views/admins/ec_templates/index.html.erb new file mode 100644 index 000000000..f4d4cce15 --- /dev/null +++ b/app/views/admins/ec_templates/index.html.erb @@ -0,0 +1,15 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('导入模板管理') %> +<% end %> + +
+ <%= javascript_void_link '新增', class: 'btn btn-primary', data: { toggle: 'modal', target: '.ec-templates-new-add' } %> +
+ + +
+ <%= render(partial: 'admins/ec_templates/shared/list', locals: { templates: @templates }) %> +
+ +<%= render partial: "admins/ec_templates/shared/templates_add_modal" %> +<%#= render partial: "admins/auth_schools/shared/user_add_modal" %> \ No newline at end of file diff --git a/app/views/admins/ec_templates/index.js.erb b/app/views/admins/ec_templates/index.js.erb new file mode 100644 index 000000000..1897fad3d --- /dev/null +++ b/app/views/admins/ec_templates/index.js.erb @@ -0,0 +1 @@ +$(".ec-templates-list-container").html("<%= j render partial: "admins/ec_templates/shared/list", locals: {templates: @templates} %>") \ No newline at end of file diff --git a/app/views/admins/ec_templates/shared/_list.html.erb b/app/views/admins/ec_templates/shared/_list.html.erb new file mode 100644 index 000000000..3c47896ae --- /dev/null +++ b/app/views/admins/ec_templates/shared/_list.html.erb @@ -0,0 +1,35 @@ + + + + + + + + + <% if templates.size > 0 %> + <% templates.each_with_index do |t, index| %> + <% attachment = t.attachments.first %> + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号模板名称上传模板操作
<%= list_index_no(@params_page.to_i, index) %><%= t.name %> + <% if attachment.present? %> + <%= link_to "#{attachment.try(:filename)}",attachment_path(attachment), target: "_blank" %> + <% end %> + + <%= link_to "".html_safe, + "javascript:void(0)", data: {"id": "#{t.id}", "template-id": "#{attachment.present? ? attachment.id : "-1"}", + msg: "编辑", name: "#{t.name}", "template_name": "#{attachment.try(:filename)}"}, class: "edit-template-content" %> + + <%= link_to "".html_safe, admins_ec_template_path(t.id), method: :delete, data: {confirm: "确认删除吗?"}, remote: true, title: "删除" %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: templates } %> \ No newline at end of file diff --git a/app/views/admins/ec_templates/shared/_templates_add_modal.html.erb b/app/views/admins/ec_templates/shared/_templates_add_modal.html.erb new file mode 100644 index 000000000..c27767655 --- /dev/null +++ b/app/views/admins/ec_templates/shared/_templates_add_modal.html.erb @@ -0,0 +1,44 @@ + diff --git a/app/views/admins/graduation_standards/create_standard.js.erb b/app/views/admins/graduation_standards/create_standard.js.erb new file mode 100644 index 000000000..45ca1ee0c --- /dev/null +++ b/app/views/admins/graduation_standards/create_standard.js.erb @@ -0,0 +1,3 @@ +$(".graduation-standards-add").removeClass("show").modal("hide") +$(".graduation-standards-list-container").html("<%= j render partial: "admins/graduation_standards/shared/list", locals: { standards: @standards } %>") +show_success_flash() \ No newline at end of file diff --git a/app/views/admins/graduation_standards/index.html.erb b/app/views/admins/graduation_standards/index.html.erb new file mode 100644 index 000000000..8d0dee758 --- /dev/null +++ b/app/views/admins/graduation_standards/index.html.erb @@ -0,0 +1,14 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('毕业要求通用标准') %> +<% end %> + +
+ <%= javascript_void_link '新增', class: 'btn btn-primary standard-create-modal', data: { toggle: 'modal', target: '.graduation-standards-add', + id: "-1", content: "", msg: "添加" } %> +
+ +
+ <%= render(partial: 'admins/graduation_standards/shared/list', locals: { standards: @standards }) %> +
+ +<%= render partial: "admins/graduation_standards/shared/add_standard_modal" %> \ No newline at end of file diff --git a/app/views/admins/graduation_standards/index.js.erb b/app/views/admins/graduation_standards/index.js.erb new file mode 100644 index 000000000..1a83aaad3 --- /dev/null +++ b/app/views/admins/graduation_standards/index.js.erb @@ -0,0 +1 @@ +$(".graduation-standards-list-container").html("<%= j render partial: "admins/graduation_standards/shared/list", locals: { standards: @standards } %>") \ No newline at end of file diff --git a/app/views/admins/graduation_standards/shared/_add_standard_modal.html.erb b/app/views/admins/graduation_standards/shared/_add_standard_modal.html.erb new file mode 100644 index 000000000..9b339bf56 --- /dev/null +++ b/app/views/admins/graduation_standards/shared/_add_standard_modal.html.erb @@ -0,0 +1,22 @@ + \ No newline at end of file diff --git a/app/views/admins/graduation_standards/shared/_list.html.erb b/app/views/admins/graduation_standards/shared/_list.html.erb new file mode 100644 index 000000000..55106c290 --- /dev/null +++ b/app/views/admins/graduation_standards/shared/_list.html.erb @@ -0,0 +1,27 @@ + + + + + + + + <% if standards.size > 0 %> + <% standards.each_with_index do |standard, index| %> + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
序号通用标准操作
<%= list_index_no(@params_page.to_i, index) %><%= standard.content %> + <%= javascript_void_link "".html_safe, class: 'standard-create-modal', + data: { toggle: 'modal', target: '.graduation-standards-add', id: "#{standard.id}", content: "#{standard.content}", msg: "编辑" }, title: "编辑" %> + + <%= link_to "".html_safe, admins_graduation_standard_path(standard), method: :delete, data: {confirm: "确认删除吗?"}, remote: true, title: "删除" %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: standards } %> \ No newline at end of file diff --git a/app/views/admins/help_centers/edit.html.erb b/app/views/admins/help_centers/edit.html.erb new file mode 100644 index 000000000..29137c39c --- /dev/null +++ b/app/views/admins/help_centers/edit.html.erb @@ -0,0 +1,15 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('帮助中心') %> +<% end %> + +
+ <%= simple_form_for(@doc, url: admins_help_center_path) do |f| %> +
+ <%= text_area_tag('help_center', @doc.help_center, style: 'display: none') %> +
+ +
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/admins/library_applies/shared/_list.html.erb b/app/views/admins/library_applies/shared/_list.html.erb index c6f9825dc..783d0db30 100644 --- a/app/views/admins/library_applies/shared/_list.html.erb +++ b/app/views/admins/library_applies/shared/_list.html.erb @@ -27,7 +27,7 @@ <% end %> - <%= user.real_name %> + <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> <%= link_to library.title, library_path(library), :target => "_blank" %> <%= overflow_hidden_span library.content[0..50]%> <%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %> diff --git a/app/views/admins/major_informations/index.html.erb b/app/views/admins/major_informations/index.html.erb new file mode 100644 index 000000000..41570ec06 --- /dev/null +++ b/app/views/admins/major_informations/index.html.erb @@ -0,0 +1,7 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('本科专业目录') %> +<% end %> + +
+ <%= render(partial: 'admins/major_informations/shared/list', locals: { majors: @disciplines }) %> +
diff --git a/app/views/admins/major_informations/shared/_list.html.erb b/app/views/admins/major_informations/shared/_list.html.erb new file mode 100644 index 000000000..0821f7478 --- /dev/null +++ b/app/views/admins/major_informations/shared/_list.html.erb @@ -0,0 +1,48 @@ +
+ <% if @disciplines.size > 0 %> + <% @disciplines.each_with_index do |d,index| %> +
+ +
+
+ + + + + + + + + + <% d.ec_discipline_firsts.each do |f| %> + <% f.ec_majors.each_with_index do |m, index| %> + + + + + + + + <% end %> + <% end %> + + +
一级学科代码一级学科名称专业代码专业名称认证学校数量
<%= index == 0 ? f.code : "" %><%= index == 0 ? f.name : "" %><%= m.code %><%= m.name %><%= m.schools.size.to_i %>
+
+
+
+ <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> +
+<%= render partial: 'admins/shared/paginate', locals: { objects: @disciplines } %> \ No newline at end of file diff --git a/app/views/admins/project_package_applies/shared/_list.html.erb b/app/views/admins/project_package_applies/shared/_list.html.erb index 736d939f9..d94c96184 100644 --- a/app/views/admins/project_package_applies/shared/_list.html.erb +++ b/app/views/admins/project_package_applies/shared/_list.html.erb @@ -27,7 +27,7 @@ <% end %> - <%= user.real_name %> + <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> <%= link_to package.title, "/crowdsourcing/#{package.id}", :target => "_blank" %> <%= overflow_hidden_span package.content[0..50] %> <%= apply.updated_at.strftime('%Y-%m-%d %H:%M') %> diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index 96d67b52a..da65099ca 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -56,7 +56,8 @@ <%= sidebar_item_group('#apply-review-submenu', '审核', icon: 'gavel') do %>
  • <%= sidebar_item(admins_identity_authentications_path, '实名认证', icon: 'id-card-o', controller: 'admins-identity_authentications') %>
  • <%= sidebar_item(admins_professional_authentications_path, '职业认证', icon: 'drivers-license', controller: 'admins-professional_authentications') %>
  • -
  • <%= sidebar_item(admins_department_applies_path, '部门审批', icon: 'building', controller: 'admins-department_applies') %>
  • +
  • <%= sidebar_item(admins_department_applies_path, '部门审批', icon: 'newspaper-o', controller: 'admins-department_applies') %>
  • +
  • <%= sidebar_item(admins_unit_applies_path, '单位审批', icon: 'building-o', controller: 'admins-unit_applies') %>
  • <%= sidebar_item(admins_shixun_authorizations_path, '实训发布', icon: 'object-ungroup', controller: 'admins-shixun_authorizations') %>
  • <%= sidebar_item(admins_subject_authorizations_path, '实践课程发布', icon: 'object-group', controller: 'admins-subject_authorizations') %>
  • <%= sidebar_item(admins_library_applies_path, '教学案例发布', icon: 'language', controller: 'admins-library_applies') %>
  • @@ -64,6 +65,25 @@
  • <%= sidebar_item(admins_video_applies_path, '视频发布', icon: 'film', controller: 'admins-video_applies') %>
  • <% end %> + +
  • + <%= sidebar_item_group('#major-identification-submenu', '工程认证', icon: 'anchor') do %> +
  • <%= sidebar_item(admins_major_informations_path, '本科专业目录', icon: 'outdent', controller: 'admins-major_informations') %>
  • +
  • <%= sidebar_item(admins_auth_schools_path, '认证单位列表', icon: 'th', controller: 'admins-auth_schools') %>
  • +
  • <%= sidebar_item(admins_graduation_standards_path, '毕业要求通用标准', icon: 'file-word-o', controller: 'admins-graduation_standards') %>
  • +
  • <%= sidebar_item(admins_ec_templates_path, '导入模板管理', icon: 'file-excel-o', controller: 'admins-ec_templates') %>
  • + <% end %> + + +
  • + <%= sidebar_item_group('#helps-submenu', '帮助中心', icon: 'info-circle') do %> +
  • <%= sidebar_item(edit_admins_about_path, '关于我们', icon: 'smile-o', controller: 'admins-abouts') %>
  • +
  • <%= sidebar_item(edit_admins_contact_us_path, '联系我们', icon: 'commenting-o', controller: 'admins-contact_us') %>
  • +
  • <%= sidebar_item(admins_cooperatives_path, '合作伙伴', icon: 'handshake-o', controller: 'admins-cooperatives') %>
  • +
  • <%= sidebar_item(edit_admins_agreement_path, '服务协议', icon: 'file-text-o', controller: 'admins-agreements') %>
  • +
  • <%= sidebar_item(edit_admins_help_center_path, '帮助中心', icon: 'question-circle-o', controller: 'admins-help_centers') %>
  • + <% end %> +
  • <%= sidebar_item('/', '返回主站', icon: 'sign-out', controller: 'root') %>
  • \ No newline at end of file diff --git a/app/views/admins/shared/after_render_js_hook.js.erb b/app/views/admins/shared/after_render_js_hook.js.erb index efc1e9295..b0823d34a 100644 --- a/app/views/admins/shared/after_render_js_hook.js.erb +++ b/app/views/admins/shared/after_render_js_hook.js.erb @@ -1,4 +1,4 @@ ; -$('[data-toggle="tooltip"]').tooltip(); +$('[data-toggle="tooltip"]').tooltip({ trigger : 'hover' }); $('[data-toggle="popover"]').popover(); $('img.preview-image').bootstrapViewer(); \ No newline at end of file diff --git a/app/views/admins/shared/delete.js.erb b/app/views/admins/shared/delete.js.erb index 74512d55b..0da435fd7 100644 --- a/app/views/admins/shared/delete.js.erb +++ b/app/views/admins/shared/delete.js.erb @@ -1,22 +1,27 @@ var deleteRow = $('<%= params[:element] %>'); var refreshUrl = '<%= params[:refresh_url] %>'; +var notRefresh = <%= !!params[:not_refresh] %>; $.notify({ message: '操作成功' },{ type: 'success' }); -var refreshFunc = function(url) { - $.ajax({ - url: url.length > 0 ? url : window.location.href, - method: 'GET', - dataType: "script" - }) -} +if (!notRefresh) { + var refreshFunc = function(url) { + $.ajax({ + url: url.length > 0 ? url : window.location.href, + method: 'GET', + dataType: "script" + }) + } -if(deleteRow.length > 0){ - var needRefresh = deleteRow.siblings().length == 0; + if(deleteRow.length > 0){ + var needRefresh = deleteRow.siblings().length == 0; - deleteRow.remove(); + deleteRow.remove(); - if(needRefresh){ refreshFunc(refreshUrl); } + if(needRefresh){ refreshFunc(refreshUrl); } + } else { + refreshFunc(refreshUrl); + } } else { - refreshFunc(refreshUrl); + deleteRow.remove(); } \ No newline at end of file diff --git a/app/views/admins/shixun_authorizations/shared/_list.html.erb b/app/views/admins/shixun_authorizations/shared/_list.html.erb index ce3b4ca43..042e4096e 100644 --- a/app/views/admins/shixun_authorizations/shared/_list.html.erb +++ b/app/views/admins/shixun_authorizations/shared/_list.html.erb @@ -27,7 +27,7 @@ <% end %> - <%= user.real_name %> + <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> <%= link_to "/shixuns/#{shixun.identifier}", target: '_blank' do %> <%= overflow_hidden_span shixun.name, width: 300 %> diff --git a/app/views/admins/shixun_settings/shared/_td.html.erb b/app/views/admins/shixun_settings/shared/_td.html.erb index efdec4f8d..f72dc8a38 100644 --- a/app/views/admins/shixun_settings/shared/_td.html.erb +++ b/app/views/admins/shixun_settings/shared/_td.html.erb @@ -21,7 +21,7 @@ <%= image_tag(imageUrl, width: 60, height: 40, class: "preview-image shixun-image-#{shixun.id}", data: { toggle: 'tooltip', title: '点击预览' }, style: imageExists ? '' : 'display:none') %> <%= javascript_void_link imageExists ? '重新上传' : '上传图片', class: 'action upload-shixun-image-action', data: { source_id: shixun.id, source_type: 'Shixun', toggle: 'modal', target: '.admin-upload-file-modal' } %> -<%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.login}",target:'_blank' %> +<%= link_to shixun.owner.try(:real_name),"/users/#{shixun.owner.login}",target:'_blank' %> <% if shixun.status.to_i < 3 %> <%= link_to "关闭", admins_shixun_setting_path(shixun,status:3,page_no:page_no),method: :put, :class => "", :remote => true %> diff --git a/app/views/admins/shixuns/shared/_list.html.erb b/app/views/admins/shixuns/shared/_list.html.erb index 64fb32d56..7e96eb0fa 100644 --- a/app/views/admins/shixuns/shared/_list.html.erb +++ b/app/views/admins/shixuns/shared/_list.html.erb @@ -17,7 +17,7 @@ <% if shixuns.present? %> <% shixuns.each_with_index do |shixun,index| %> - <%= (@params_page.to_i - 1) * 20 + index + 1%> + <%= list_index_no(@params_page.to_i, index) %> <%= shixun.identifier %> <%= link_to overflow_hidden_span(shixun.name), "/shixuns/#{shixun.identifier}", :target => "_blank", :title => shixun.name %> @@ -33,7 +33,7 @@ <%= shixun.challenges.where(:st => 0).size %> <%= shixun.challenges.where(:st => 1).size %> <%= shixun_authentication_status shixun %> - <%= link_to shixun.owner.try(:show_real_name),"/users/#{shixun.owner.try(:login)}",target:'_blank' %> + <%= link_to shixun.owner.try(:real_name),"/users/#{shixun.owner.try(:login)}",target:'_blank' %> <%= format_time shixun.created_at %> class="ml-3 mr5 magic-checkbox" id="join_teacher_homepage_<%= shixun.id %>"> diff --git a/app/views/admins/subject_authorizations/shared/_list.html.erb b/app/views/admins/subject_authorizations/shared/_list.html.erb index 7b8da800d..28a699e22 100644 --- a/app/views/admins/subject_authorizations/shared/_list.html.erb +++ b/app/views/admins/subject_authorizations/shared/_list.html.erb @@ -29,7 +29,7 @@ <% end %> - <%= user.real_name %> + <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> <%= link_to "/paths/#{subject.id}", target: '_blank' do %> <%= overflow_hidden_span subject.name, width: 300 %> diff --git a/app/views/admins/unit_applies/edit.js.erb b/app/views/admins/unit_applies/edit.js.erb new file mode 100644 index 000000000..15fc1f4c2 --- /dev/null +++ b/app/views/admins/unit_applies/edit.js.erb @@ -0,0 +1,56 @@ +$("body").append("<%= j render partial: "admins/unit_applies/shared/edit_modal",locals: {apply: @unit_apply, schools: @all_schools} %>") +var uni_edit_modal = $(".admin-unit-edit-modal") +uni_edit_modal.modal("show") + +uni_edit_modal.on("hidden.bs.modal",function () { + $(".admin-unit-edit-modal").remove() + $("body").removeClass("modal-open") +}) + +// 初始化学校选择器 +var matcherFunc = function(params, data){ + if ($.trim(params.term) === '') { + return data; + } + if (typeof data.text === 'undefined') { + return null; + } + if (data.name && data.name.indexOf(params.term) > -1) { + var modifiedData = $.extend({}, data, true); + return modifiedData; + } + + // Return `null` if the term should not be displayed + return null; +} +$.ajax({ + url: '/api/schools/for_option.json', + dataType: 'json', + type: 'GET', + success: function(data) { + $("#all-schools").select2({ + theme: 'bootstrap4', + placeholder: '查询学校/单位', + minimumInputLength: 1, + data: data.schools, + templateResult: function (item) { + if(!item.id || item.id === '') return item.text; + return item.name; + }, + templateSelection: function(item){ + return item.name || item.text; + }, + matcher: matcherFunc + }) + } +}); + +$("#all-schools").select2({}) +$("#show-province-<%= @unit_apply.id %>").select2() +$("#schoolCity_<%= @unit_apply.id %>").select2() + +// **************** 地区选择 **************** +$('.province-city-select').cxSelect({ + url: '/javascripts/educoder/province-data.json', + selects: ['province-select', 'city-select'] +}); \ No newline at end of file diff --git a/app/views/admins/unit_applies/index.html.erb b/app/views/admins/unit_applies/index.html.erb new file mode 100644 index 000000000..2b715b87c --- /dev/null +++ b/app/views/admins/unit_applies/index.html.erb @@ -0,0 +1,17 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('单位审批') %> +<% end %> + +
    + <%= form_tag(admins_unit_applies_path(unsafe_params), method: :get, class: 'form-inline search-form mt-3', remote: true) do %> + <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '单位名称检索') %> + <%= submit_tag('搜索', class: 'btn btn-primary ml-3','data-disable-with':"搜索中...") %> + <%= link_to "清除",admins_unit_applies_path(keyword:nil),class:"btn btn-default",remote:true %> + <% end %> +
    + +
    + <%= render(partial: 'admins/unit_applies/shared/list', locals: { applies: @unit_applies }) %> +
    + +<%= render(partial: 'admins/shared/admin_common_refuse_modal') %> diff --git a/app/views/admins/unit_applies/index.js.erb b/app/views/admins/unit_applies/index.js.erb new file mode 100644 index 000000000..d9297d51a --- /dev/null +++ b/app/views/admins/unit_applies/index.js.erb @@ -0,0 +1 @@ +$(".unit-applies-list-container").html("<%= j render partial: "admins/unit_applies/shared/list", locals: {applies: @unit_applies} %>") diff --git a/app/views/admins/unit_applies/shared/_apply_item.html.erb b/app/views/admins/unit_applies/shared/_apply_item.html.erb new file mode 100644 index 000000000..084826d72 --- /dev/null +++ b/app/views/admins/unit_applies/shared/_apply_item.html.erb @@ -0,0 +1,17 @@ +<%= apply.id %> +<%= overflow_hidden_span apply.name %> + + <%= "#{apply&.province.to_s}"+"#{apply&.city.to_s}" %> + +<%= overflow_hidden_span apply.address %> +<%= link_to apply&.user&.real_name, "/users/#{apply&.user&.login}", target: "_blank" %> +<%= format_time apply.created_at %> + + <%= agree_link '批准', agree_admins_unit_apply_path(apply, element: ".unit-apply-#{apply.id}"), 'data-confirm': '确认批准通过?' %> + <%= javascript_void_link('删除', class: 'action refuse-action', + data: { + toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id, title: "删除原因", type: "delete", + url: admins_unit_apply_path(apply, tip: "unapplied", element: ".unit-apply-#{apply.id}") + }) %> + <%= link_to "更改",edit_admins_unit_apply_path(apply), remote: true, class:"action",'data-disable-with': '打开中...' %> + \ No newline at end of file diff --git a/app/views/admins/unit_applies/shared/_edit_modal.html.erb b/app/views/admins/unit_applies/shared/_edit_modal.html.erb new file mode 100644 index 000000000..6f8995ae0 --- /dev/null +++ b/app/views/admins/unit_applies/shared/_edit_modal.html.erb @@ -0,0 +1,43 @@ + \ No newline at end of file diff --git a/app/views/admins/unit_applies/shared/_list.html.erb b/app/views/admins/unit_applies/shared/_list.html.erb new file mode 100644 index 000000000..c28ce7967 --- /dev/null +++ b/app/views/admins/unit_applies/shared/_list.html.erb @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + <% if applies.present? %> + <% applies.each do |apply| %> + + <%= render partial: "admins/unit_applies/shared/apply_item", locals: {apply: apply} %> + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
    ID单位名称地区详细地址申请者<%= sort_tag('创建于', name: 'created_at', path: admins_unit_applies_path) %>操作
    + +<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %> \ No newline at end of file diff --git a/app/views/admins/unit_applies/update.js.erb b/app/views/admins/unit_applies/update.js.erb new file mode 100644 index 000000000..c710f46b5 --- /dev/null +++ b/app/views/admins/unit_applies/update.js.erb @@ -0,0 +1,3 @@ +$('.modal.admin-unit-edit-modal').modal('hide'); +$('.unit-applies-list-table .unit-apply-<%= @unit_apply.id %>').remove() +$.notify({ message: '操作成功' }); \ No newline at end of file diff --git a/app/views/admins/video_applies/shared/_list.html.erb b/app/views/admins/video_applies/shared/_list.html.erb index 8ddbfb3ca..5e472bd4b 100644 --- a/app/views/admins/video_applies/shared/_list.html.erb +++ b/app/views/admins/video_applies/shared/_list.html.erb @@ -28,7 +28,7 @@ <% end %> - <%= user.real_name %> + <%= link_to user&.real_name,"/users/#{user&.login}", target: "_blank" %> <%= link_to video.title, video.file_url, :target => "_blank" %> <%= video.filesize&.to_s(:human_size) %> <%= link_to "播放视频",video.file_url, target: "_blank" %> diff --git a/app/views/challenges/edit.json.jbuilder b/app/views/challenges/edit.json.jbuilder index 5ae15cf67..3e7f5b425 100644 --- a/app/views/challenges/edit.json.jbuilder +++ b/app/views/challenges/edit.json.jbuilder @@ -16,7 +16,7 @@ elsif @tab == 1 json.has_web_route @shixun.has_web_route? json.test_sets @challenge.test_sets do |set| json.hidden (set.is_public ? 0 : 1) - json.(set, :input, :output, :score) + json.(set, :input, :output, :score, :match_rule) end elsif @tab == 2 # 参考答案 diff --git a/app/views/course_stages/edit.json.jbuilder b/app/views/course_stages/edit.json.jbuilder new file mode 100644 index 000000000..f76efb15f --- /dev/null +++ b/app/views/course_stages/edit.json.jbuilder @@ -0,0 +1,11 @@ +json.stage_id @stage.id +json.stage_name @stage.name +json.stage_description @stage.description +json.delete_path "/course_stages/#{@stage.id}" +json.shixuns_list do + json.array! @stage.shixuns.each do |shixun| + json.shixun_identifier shixun.identifier + json.shixun_name shixun.name + json.shixun_id shixun.id + end +end \ No newline at end of file diff --git a/app/views/courses/online_learning.json.jbuilder b/app/views/courses/online_learning.json.jbuilder index bec8ff301..b48cd9e23 100644 --- a/app/views/courses/online_learning.json.jbuilder +++ b/app/views/courses/online_learning.json.jbuilder @@ -2,10 +2,11 @@ json.stages @stages do |stage| json.partial! 'stages/stage', locals: {stage: stage, user:@user, subject:@subject} end -json.description @subject&.description +# json.description @subject&.description json.start_learning @start_learning +json.subject_id @subject.id -json.learned @start_learning ? @subject&.my_subject_progress : 0 +json.learned @start_learning ? @course.my_subject_progress : 0 -json.last_shixun @start_learning ? last_subject_shixun(@user.id, @subject) : "" \ No newline at end of file +json.last_shixun @start_learning ? last_subject_shixun(@user.id, @course) : "" \ No newline at end of file diff --git a/app/views/exercise_banks/show.json.jbuilder b/app/views/exercise_banks/show.json.jbuilder index bc7a6419c..802e863cb 100644 --- a/app/views/exercise_banks/show.json.jbuilder +++ b/app/views/exercise_banks/show.json.jbuilder @@ -2,6 +2,7 @@ if @bank.container_type == "Exercise" json.exercise do json.extract! @bank, :id, :name, :description, :is_public end + json.authorize @bank.user_id == current_user.id || current_user.admin? json.partial! "exercises/exercise_scores" @@ -20,6 +21,7 @@ else json.poll do json.extract! @bank, :id, :name, :description, :is_public end + json.authorize @bank.user_id == current_user.id || current_user.admin? json.question_types do json.q_counts @poll_questions_count diff --git a/app/views/games/show.json.jbuilder b/app/views/games/show.json.jbuilder index 607a57a15..048188746 100644 --- a/app/views/games/show.json.jbuilder +++ b/app/views/games/show.json.jbuilder @@ -1,8 +1,9 @@ json.(@base_date, :st, :discusses_count, :game_count, :record_onsume_time, :prev_game, :next_game, :praise_count, :user_praise, :time_limit, :tomcat_url, :is_teacher, :myshixun_manager, :game, :challenge, - :shixun, :myshixun) + :shixun, :myshixun, :git_url) if @shixun.vnc json.vnc_url @vnc_url + json.vnc_evaluate @vnc_evaluate end json.user do json.partial! 'users/user', user: @user diff --git a/app/views/graduation_tasks/show.json.jbuilder b/app/views/graduation_tasks/show.json.jbuilder index b5cd1620b..814cc62ce 100644 --- a/app/views/graduation_tasks/show.json.jbuilder +++ b/app/views/graduation_tasks/show.json.jbuilder @@ -1,11 +1,14 @@ json.partial! "public_navigation", locals: {graduation: @task, course: @course} json.description @task.description json.user_id @task.user_id +json.authorize @task.user_id == current_user.id || current_user.admin? # 附件 json.attachments @attachments do |attachment| json.partial! "attachments/attachment_simple", locals: {attachment: attachment} end +json.cross_comment @task.cross_comment +json.comment_status @task.comment_status if @user_course_identity == Course::STUDENT json.work_id @task.user_work(@current_user.id).try(:id) diff --git a/app/views/gtopic_banks/show.json.jbuilder b/app/views/gtopic_banks/show.json.jbuilder index 9c5226930..7ab86674d 100644 --- a/app/views/gtopic_banks/show.json.jbuilder +++ b/app/views/gtopic_banks/show.json.jbuilder @@ -1,5 +1,6 @@ json.(@bank, :id, :name, :description, :is_public, :topic_type, :topic_source, :topic_property_first, :topic_property_second, :source_unit, :topic_repeat, :province, :city) +json.authorize @bank.user_id == current_user.id || current_user.admin? json.attachment_list @bank_attachments do |attachment| json.partial! "attachments/attachment_simple", locals: {attachment: attachment} diff --git a/app/views/helps/contact.json.jbuilder b/app/views/helps/contact.json.jbuilder new file mode 100644 index 000000000..601aaa9a4 --- /dev/null +++ b/app/views/helps/contact.json.jbuilder @@ -0,0 +1,8 @@ +json.contacts do + json.array! @cooperations.each do |item| + json.extract! item, :name, :qq, :mail + json.type item.user_type_text + end +end + +json.address current_help.status \ No newline at end of file diff --git a/app/views/helps/cooperatives.json.jbuilder b/app/views/helps/cooperatives.json.jbuilder new file mode 100644 index 000000000..968cb4ea2 --- /dev/null +++ b/app/views/helps/cooperatives.json.jbuilder @@ -0,0 +1,11 @@ +json.data do + json.array! @data.each do |type, objs| + json.name I18n.t("enumerize.coo_img.img_type.#{type}") + json.values do + json.array! objs.sort_by(&:position).each do |obj| + json.img obj.url_states || (Util::FileManage.exist?('CooImg', obj.id) ? Util::FileManage.disk_file_url('CooImg', obj.id) : '') + json.url obj.src_states + end + end + end +end \ No newline at end of file diff --git a/app/views/homework_banks/show.json.jbuilder b/app/views/homework_banks/show.json.jbuilder index 34ca5ec25..f3785173a 100644 --- a/app/views/homework_banks/show.json.jbuilder +++ b/app/views/homework_banks/show.json.jbuilder @@ -1,4 +1,5 @@ json.(@bank, :id, :name, :description, :homework_type, :is_public, :min_num, :max_num, :base_on_project, :reference_answer) +json.authorize @bank.user_id == current_user.id || current_user.admin? json.attachments @bank_attachments do |attachment| json.partial! "attachments/attachment_simple", locals: {attachment: attachment} diff --git a/app/views/homework_commons/_student_btn_check.json.jbuilder b/app/views/homework_commons/_student_btn_check.json.jbuilder index 7b34622fa..c3cca6b48 100644 --- a/app/views/homework_commons/_student_btn_check.json.jbuilder +++ b/app/views/homework_commons/_student_btn_check.json.jbuilder @@ -5,6 +5,8 @@ if identity == Course::STUDENT json.task_operation task_operation_url(myshixun, shixun) json.view_report work.work_status > 0 json.commit_des commit_des_status(work, homework) + json.redo_work (homework.end_or_late ? false : student_redo_work(work, homework)) + json.myshixun_identifier myshixun&.identifier else json.work_statuses student_work_status(homework, work.user_id, homework.course, work) end diff --git a/app/views/homework_commons/shixuns.json.jbuilder b/app/views/homework_commons/shixuns.json.jbuilder index bd97f5e8d..79f22e42a 100644 --- a/app/views/homework_commons/shixuns.json.jbuilder +++ b/app/views/homework_commons/shixuns.json.jbuilder @@ -1,4 +1,4 @@ -# json.shixun_list @shixuns do |shixun| +# json.shixun_lists @shixuns do |shixun| # json.shixun_identifier shixun.identifier # json.name shixun.name # json.creator shixun.user&.full_name diff --git a/app/views/searchs/index.json.jbuilder b/app/views/searchs/index.json.jbuilder index 5fa0c2744..e12ebbca8 100644 --- a/app/views/searchs/index.json.jbuilder +++ b/app/views/searchs/index.json.jbuilder @@ -6,6 +6,12 @@ json.results do json.title highlights.delete(:name)&.join('...') || obj.searchable_title # json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('
    ') + + # 去除开头标点符号 + reg = /^[,。?:;‘’!“”—……、]/ + highlights[:description]&.first&.sub!(reg, '') + highlights[:content]&.first&.sub!(reg, '') + json.content highlights end end \ No newline at end of file diff --git a/app/views/shixun_lists/index.json.jbuilder b/app/views/shixun_lists/index.json.jbuilder new file mode 100644 index 000000000..d6c651743 --- /dev/null +++ b/app/views/shixun_lists/index.json.jbuilder @@ -0,0 +1,22 @@ +json.shixuns_count @results.total_count + +json.shixun_list do + json.array! @results.with_highlights(multiple: true) do |obj, highlights| + json.merge! obj.to_searchable_json + json.challenge_names obj.challenges.pluck(:subject) + + # 去除开头标点符号 + reg = /^[,。?:;‘’!“”—……、]/ + highlights[:description]&.first&.sub!(reg, '') + highlights[:content]&.first&.sub!(reg, '') + + json.title highlights.delete(:name)&.join('...') || obj.searchable_title + json.description highlights[:description]&.join('...') || Util.extract_content(obj.description)[0..300] + + json.content highlights + json.level level_to_s(obj.trainee) + json.subjects obj.subjects.uniq do |subject| + json.(subject, :id, :name) + end + end +end \ No newline at end of file diff --git a/app/views/shixuns/_right.json.jbuilder b/app/views/shixuns/_right.json.jbuilder index 694b672fb..e6f839aa5 100644 --- a/app/views/shixuns/_right.json.jbuilder +++ b/app/views/shixuns/_right.json.jbuilder @@ -3,14 +3,14 @@ json.creator do json.partial! 'users/user', locals: { user: shixun.owner } end -# 推荐实训 -json.recommands do - json.partial! 'shap_shixun', locals: { shixuns: recommend_shixun(shixun) } -end - # 相关路径 json.paths do - json.partial! 'subjects/subject', locals: {subjects: relation_path(shixun)} + json.partial! 'subjects/subject', locals: {subjects: shixun.relation_path} +end + +# 推荐实训 +json.recommands do + json.partial! 'shap_shixun', locals: { shixuns: shixun.relation_path.size > 0 ? recommend_shixun(shixun) : [] } end # 技能标签 diff --git a/app/views/shixuns/secret_repository.json.jbuilder b/app/views/shixuns/secret_repository.json.jbuilder new file mode 100644 index 000000000..482a683a8 --- /dev/null +++ b/app/views/shixuns/secret_repository.json.jbuilder @@ -0,0 +1,8 @@ +json.trees @trees + +if @trees.present? + json.partial! 'shixuns/commit', locals: { commits: @latest_commit } +end + +json.git_url @repo_url +json.secret_dir_path @shixun.shixun_secret_repository&.secret_dir_path \ No newline at end of file diff --git a/app/views/shixuns/settings.json.jbuilder b/app/views/shixuns/settings.json.jbuilder index e81498058..3441a0a06 100644 --- a/app/views/shixuns/settings.json.jbuilder +++ b/app/views/shixuns/settings.json.jbuilder @@ -22,6 +22,7 @@ json.shixun do json.hide_code @shixun.hide_code # 隐藏代码窗口 json.code_hidden @shixun.code_hidden # 代码目录隐藏 json.vnc @shixun.vnc + json.vnc_evaluate @shixun.vnc_evaluate #json.exec_time @shixun.exec_time json.webssh @shixun.webssh json.multi_webssh @shixun.multi_webssh @@ -29,6 +30,9 @@ json.shixun do json.scope_partment @shixun.schools.map(&:name) # 公开范围 json.opening_time @shixun.opening_time json.forbid_copy @shixun.forbid_copy + json.code_edit_permission @shixun.code_edit_permission # tpi学员是否有编辑所有代码的权限 + # 私密仓库 + json.is_secret_repository @shixun.shixun_secret_repository.present? # 实训服务配置 json.shixun_service_configs do diff --git a/app/views/shixuns/shixun_list.json.jbuilder b/app/views/shixuns/shixun_list.json.jbuilder index 13c556014..2f1d4905c 100644 --- a/app/views/shixuns/shixun_list.json.jbuilder +++ b/app/views/shixuns/shixun_list.json.jbuilder @@ -1,15 +1,17 @@ -json.shixun_list @shixuns do |shixun| - json.shixun_id shixun.id - json.identifier shixun.identifier - json.shixun_name shixun.name - json.description shixun.description - json.myshixuns_count shixun.myshixuns_count - json.school shixun.user&.school_name - json.creator shixun.user&.full_name - json.level level_to_s(shixun.trainee) - json.subjects shixun.subjects do |subject| - json.(subject, :id, :name) - end -end +json.shixuns_count @total_count + +json.shixun_list do + json.array! @shixuns.with_highlights(multiple: true) do |obj, highlights| + puts obj + json.merge! obj.to_searchable_json + json.challenge_names obj.challenges.pluck(:subject) -json.shixuns_count @total_count \ No newline at end of file + json.title highlights.delete(:name)&.join('...') || obj.searchable_title + # json.description highlights.values[0,5].each { |arr| arr.is_a?(Array) ? arr.join('...') : arr }.join('
    ') + json.content highlights + json.level level_to_s(obj.trainee) + json.subjects obj.subjects.uniq do |subject| + json.(subject, :id, :name) + end + end +end \ No newline at end of file diff --git a/app/views/shixuns/show.json.jbuilder b/app/views/shixuns/show.json.jbuilder index 8e49a99f4..4a0c3ebd6 100644 --- a/app/views/shixuns/show.json.jbuilder +++ b/app/views/shixuns/show.json.jbuilder @@ -2,3 +2,4 @@ json.fork_from @fork_from json.identity User.current.shixun_identity(@shixun) json.power @power json.partial! 'shixuns/top', locals: { shixun: @shixun, current_myshixun: @current_myshixun } +json.secret_repository @shixun.shixun_secret_repository.present? diff --git a/app/views/student_works/shixun_work_comment.json.jbuilder b/app/views/student_works/shixun_work_comment.json.jbuilder new file mode 100644 index 000000000..f9f47cba5 --- /dev/null +++ b/app/views/student_works/shixun_work_comment.json.jbuilder @@ -0,0 +1,3 @@ +json.comment_id @comment.id +json.status 0 +json.message "评阅成功" \ No newline at end of file diff --git a/app/views/student_works/shixun_work_report.json.jbuilder b/app/views/student_works/shixun_work_report.json.jbuilder index 0ba6bfa5b..2c9558fdc 100644 --- a/app/views/student_works/shixun_work_report.json.jbuilder +++ b/app/views/student_works/shixun_work_report.json.jbuilder @@ -36,6 +36,10 @@ if @shixun challenge_score = @homework.challenge_score game.challenge_id json.game_score_full challenge_score json.game_score @work.work_challenge_score game, challenge_score + challenge_comment = @work.shixun_work_comments.find_by(challenge_id: game.challenge_id) + json.challenge_comment challenge_comment&.comment + json.challenge_comment_hidden @user_course_identity < Course::STUDENT ? challenge_comment&.hidden_comment : nil + json.comment_id challenge_comment&.id end end @@ -46,6 +50,17 @@ if @shixun json.user_id @user.id json.username @user.real_name json.student_id @user.student_id + json.image_url url_to_avatar(@user) + json.complete_count @work.myshixun&.passed_count + json.challenges_count @shixun.challenges_count + json.efficiency @homework.work_efficiency ? number_with_precision(@work.efficiency, precision: 2) : nil + json.max_efficiency @homework.work_efficiency ? number_with_precision(@homework.max_efficiency, precision: 2) : nil + json.passed_time @work.myshixun&.passed_time + + # 评阅信息 + json.work_comment @comment&.comment + json.work_comment_hidden @user_course_identity < Course::STUDENT ? @comment&.hidden_comment : nil + json.comment_id @comment&.id # 图形统计 # 1: 效率 diff --git a/app/views/task_banks/show.json.jbuilder b/app/views/task_banks/show.json.jbuilder index b929fafd8..ab53399e1 100644 --- a/app/views/task_banks/show.json.jbuilder +++ b/app/views/task_banks/show.json.jbuilder @@ -1,5 +1,6 @@ json.(@bank, :id, :name, :description, :task_type, :is_public) # 附件 +json.authorize @bank.user_id == current_user.id || current_user.admin? json.attachments @bank_attachments do |attachment| json.partial! "attachments/attachment_simple", locals: {attachment: attachment} end diff --git a/app/views/tidings/_tiding.json.jbuilder b/app/views/tidings/_tiding.json.jbuilder index 3b70f66f1..210e5c8f8 100644 --- a/app/views/tidings/_tiding.json.jbuilder +++ b/app/views/tidings/_tiding.json.jbuilder @@ -17,8 +17,13 @@ json.homework_type homework_type json.time tiding.how_long_time json.new_tiding tiding.unread?(@onclick_time) +# 需要系统头像 +show_system_user = tiding.trigger_user_id.zero? || + (tiding.trigger_user_id == 1 && tiding.tiding_type == 'System') || + tiding.anonymous? + json.trigger_user do - if tiding.trigger_user_id.zero? + if show_system_user json.id 0 json.name "系统" json.login "" diff --git a/app/views/users/question_banks/index.json.jbuilder b/app/views/users/question_banks/index.json.jbuilder index 92dc445c7..018e78254 100644 --- a/app/views/users/question_banks/index.json.jbuilder +++ b/app/views/users/question_banks/index.json.jbuilder @@ -1,6 +1,9 @@ json.count @count -json.course_list @course_lists, partial: 'users/question_banks/shared/course_list', as: :course_list +json.course_list @course_lists do |course_list| + json.id course_list.id + json.name course_list.name +end json.question_banks @question_banks do |question_bank| json.id question_bank.id @@ -11,4 +14,5 @@ json.question_banks @question_banks do |question_bank| json.course_list_name question_bank.course_list&.name json.updated_at question_bank.updated_at json.solve_count @solve_count_map.fetch(question_bank.id, 0) + json.authorize question_bank.user_id == current_user.id || current_user.admin? end diff --git a/config/initializers/session_extenstions.rb b/config/initializers/session_extenstions.rb index 36a8ae8c7..cee3dfc06 100644 --- a/config/initializers/session_extenstions.rb +++ b/config/initializers/session_extenstions.rb @@ -1,35 +1,33 @@ -#coding=utf-8 - -module SessionExtenstions - - module EntryExtension - def compressed? - @compressed - end - - def value - if @value - begin - Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value) - rescue TypeError - compressed? ? Zlib::Inflate.inflate(@value) : @value - end - end - end - - def size - if @value.nil? - 0 - else - @value.bytesize - end - end - end - - -end - -ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1) -ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension) - - +#coding=utf-8 + +module SessionExtenstions + + module EntryExtension + def compressed? + @compressed + end + + def value + if @value + begin + Marshal.load(compressed? ? Zlib::Inflate.inflate(@value) : @value) + rescue TypeError + compressed? ? Zlib::Inflate.inflate(@value) : @value + end + end + end + + def size + if @value.nil? + 0 + else + @value.bytesize + end + end + end + + +end + +ActiveSupport::Cache::Entry.const_set("DEFAULT_COMPRESS_LIMIT", 1) +ActiveSupport::Cache::Entry.send(:prepend, SessionExtenstions::EntryExtension) diff --git a/config/locales/coo_imgs/zh-CN.yml b/config/locales/coo_imgs/zh-CN.yml new file mode 100644 index 000000000..737d3bed5 --- /dev/null +++ b/config/locales/coo_imgs/zh-CN.yml @@ -0,0 +1,7 @@ +zh-CN: + enumerize: + coo_img: + img_type: + com_coop: '知名企业' + edu_coop: '各类院校' + alliance_coop: '产学联盟' \ No newline at end of file diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml index e6e8e676d..21c020d04 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -202,6 +202,7 @@ 2_end: "别人对你的匿评发起的申诉申请:%s,审核未通过" StudentWork: Apply_end: "发起了匿评申诉申请:%s" + HomeworkCommon_end: "发起了匿评申诉申请:%s" System_end: "有人对你的匿评发起了申诉:%s" Department_end: "你选填的二级单位:%s(%s)因不符合规范,已被系统删除.请重新选择" Library: diff --git a/config/routes.rb b/config/routes.rb index 392429b60..b6244d555 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,12 +55,14 @@ Rails.application.routes.draw do get :homepage_info end + get :question_banks, on: :collection, to: 'users/question_banks#index' + scope module: :users do resources :courses, only: [:index] resources :shixuns, only: [:index] resources :projects, only: [:index] resources :subjects, only: [:index] - resources :question_banks, only: [:index] + # resources :question_banks, only: [:index] resource :experience_records, only: [:show] resource :grade_records, only: [:show] resource :watch, only: [:create, :destroy] @@ -159,6 +161,7 @@ Rails.application.routes.draw do get :picture_display get :sync_codes get :close_webssh + get :reset_vnc_link get :get_answer_info get :unlock_answer get :check_test_sets @@ -171,7 +174,10 @@ Rails.application.routes.draw do end end + resources :shixun_lists + resources :shixuns, param: :identifier do + collection do get :menus get :get_recommend_shixuns @@ -179,7 +185,7 @@ Rails.application.routes.draw do get :get_mirror_script post :apply_shixun_mirror get :download_file - get :shixun_list + get :shixun_lists end member do @@ -195,6 +201,8 @@ Rails.application.routes.draw do get :get_script_contents get :get_custom_script post :repository + post :secret_repository + post :set_secret_dir post :commits post :file_content post :update_file @@ -369,6 +377,13 @@ Rails.application.routes.draw do get 'search_slim' end + resources :course_stages, shallow: true do + member do + post :up_position + post :down_position + end + end + resources :polls, only:[:index,:new,:create] do collection do post :publish # 立即发布 @@ -438,6 +453,8 @@ Rails.application.routes.draw do post :deal_appeal_score post :cancel_appeal get :export_shixun_work_report + post :shixun_work_comment + delete :destroy_work_comment end collection do @@ -784,10 +801,42 @@ Rails.application.routes.draw do namespace :wechats do resource :js_sdk_signature, only: [:create] end + + resources :helps, only: [] do + collection do + get :about + get :contact + get :cooperatives + get :agreement + get :help_center + post :feedback + end + end end namespace :admins do get '/', to: 'dashboards#index' + resources :major_informations, only: [:index] + resources :ec_templates, only: [:index, :destroy] do + collection do + post :create_template + end + end + resources :graduation_standards, only: [:index, :destroy] do + collection do + post :create_standard + end + end + resources :auth_schools, only: [:index, :destroy] do + collection do + get :search_school + post :add_school + get :search_manager + post :add_manager + post :remove_manager + end + + end resources :dashboards, only: [:index] do collection do get :month_active_user @@ -859,7 +908,15 @@ Rails.application.routes.draw do end resources :shixuns, only: [:index,:destroy] resources :shixun_settings, only: [:index,:update] - resources :department_applies,only: [:index,:edit,:update,:destroy] do + resources :department_applies,only: [:index,:destroy] do + collection do + post :merge + end + member do + post :agree + end + end + resources :unit_applies,only: [:index,:destroy,:edit,:update] do member do post :agree end @@ -877,6 +934,17 @@ Rails.application.routes.draw do post :merge, on: :collection end resources :myshixuns, only: [:index] + + resource :about, only: [:edit, :update] + resource :agreement, only: [:edit, :update] + resource :help_center, only: [:edit, :update] + resource :contact_us, only: [:edit, :update] do + patch :update_address, on: :collection + end + resources :cooperatives, only: [:index, :create, :update, :destroy] do + post :drag, on: :collection + post :replace_image_url, on: :member + end end resources :colleges, only: [] do diff --git a/db/migrate/20190905070518_reorder_coo_img_position.rb b/db/migrate/20190905070518_reorder_coo_img_position.rb new file mode 100644 index 000000000..1aa8a6842 --- /dev/null +++ b/db/migrate/20190905070518_reorder_coo_img_position.rb @@ -0,0 +1,9 @@ +class ReorderCooImgPosition < ActiveRecord::Migration[5.2] + def change + CooImg.all.group_by(&:img_type).each do |_type, objs| + objs.sort_by(&:position).each_with_index do |obj, index| + obj.update!(position: index + 1) + end + end + end +end diff --git a/db/migrate/20190905070821_change_public_model_default_value.rb b/db/migrate/20190905070821_change_public_model_default_value.rb new file mode 100644 index 000000000..09d4af61a --- /dev/null +++ b/db/migrate/20190905070821_change_public_model_default_value.rb @@ -0,0 +1,20 @@ +class ChangePublicModelDefaultValue < ActiveRecord::Migration[5.2] + def change + #试卷的默认值的修改 + change_column_default :exercises,:show_result,0 + change_column_default :exercises, :answer_open, false + change_column_default :exercises, :score_open, false + + #问卷的默认值的修改 + change_column_default :polls, :show_result, 0 + + #实训作业/普通作业/分组作业 + change_column_default :homework_commons, :score_open, false + change_column_default :homework_commons, :work_public, false + change_column_default :homework_commons, :answer_public, false + + #毕设任务 + change_column_default :graduation_tasks, :open_score, false + change_column_default :graduation_tasks, :open_work, false + end +end diff --git a/db/migrate/20190906062930_modify_is_test_for_user.rb b/db/migrate/20190906062930_modify_is_test_for_user.rb new file mode 100644 index 000000000..f3f5bfd3b --- /dev/null +++ b/db/migrate/20190906062930_modify_is_test_for_user.rb @@ -0,0 +1,5 @@ +class ModifyIsTestForUser < ActiveRecord::Migration[5.2] + def change + change_column :users, :is_test, :integer, :limit => 1 + end +end diff --git a/db/migrate/20190906111746_gtopic_bank_is_public.rb b/db/migrate/20190906111746_gtopic_bank_is_public.rb new file mode 100644 index 000000000..193824dc4 --- /dev/null +++ b/db/migrate/20190906111746_gtopic_bank_is_public.rb @@ -0,0 +1,5 @@ +class GtopicBankIsPublic < ActiveRecord::Migration[5.2] + def change + GtopicBank.where(is_public: nil).update_all(is_public: 0) + end +end diff --git a/db/migrate/20190907014649_add_vnc_evaluate_for_shixuns.rb b/db/migrate/20190907014649_add_vnc_evaluate_for_shixuns.rb new file mode 100644 index 000000000..861c4501e --- /dev/null +++ b/db/migrate/20190907014649_add_vnc_evaluate_for_shixuns.rb @@ -0,0 +1,5 @@ +class AddVncEvaluateForShixuns < ActiveRecord::Migration[5.2] + def change + add_column :shixuns, :vnc_evaluate, :boolean, default: false + end +end diff --git a/db/migrate/20190907021100_migrate_bank_reference_id.rb b/db/migrate/20190907021100_migrate_bank_reference_id.rb new file mode 100644 index 000000000..c71034167 --- /dev/null +++ b/db/migrate/20190907021100_migrate_bank_reference_id.rb @@ -0,0 +1,31 @@ +class MigrateBankReferenceId < ActiveRecord::Migration[5.2] + def change + HomeworkBank.all.each do |bank| + if bank.homework_common + bank.homework_common.update_column("homework_bank_id", bank.id) if bank.homework_common.homework_bank_id.nil? + end + end + + GtopicBank.all.each do |bank| + if bank.graduation_topic + bank.graduation_topic.update_column("gtopic_bank_id", bank.id) if bank.graduation_topic.gtopic_bank_id.nil? + end + end + + GtaskBank.all.each do |bank| + if bank.graduation_task + bank.graduation_task.update_column("gtask_bank_id", bank.id) if bank.graduation_task.gtask_bank_id.nil? + end + end + + ExerciseBank.all.each do |bank| + if bank.container_type == 'Exercise' + exercise = Exercise.find_by(id: bank.container_id) + exercise.update_column("exercise_bank_id", bank.id) if exercise && exercise.exercise_bank_id.nil? + elsif bank.container_type == 'Poll' + poll = Poll.find_by(id: bank.container_id) + poll.update_column("exercise_bank_id", bank.id) if poll && poll.exercise_bank_id.nil? + end + end + end +end diff --git a/db/migrate/20190907061918_migrate_bank_quotes.rb b/db/migrate/20190907061918_migrate_bank_quotes.rb new file mode 100644 index 000000000..9f278860d --- /dev/null +++ b/db/migrate/20190907061918_migrate_bank_quotes.rb @@ -0,0 +1,28 @@ +class MigrateBankQuotes < ActiveRecord::Migration[5.2] + def change + HomeworkBank.all.each do |bank| + task_count = bank.homework_commons.count + bank.update_column("quotes", task_count == 0 ? 1 : task_count) + end + + GtopicBank.all.each do |bank| + task_count = bank.graduation_topics.count + bank.update_column("quotes", task_count == 0 ? 1 : task_count) + end + + GtaskBank.all.each do |bank| + task_count = bank.graduation_tasks.count + bank.update_column("quotes", task_count == 0 ? 1 : task_count) + end + + ExerciseBank.all.each do |bank| + if bank.container_type == 'Exercise' + task_count = bank.exercises.count + bank.update_column("quotes", task_count == 0 ? 1 : task_count) + elsif bank.container_type == 'Poll' + task_count = bank.polls.count + bank.update_column("quotes", task_count == 0 ? 1 : task_count) + end + end + end +end diff --git a/db/migrate/20190909061930_create_shixun_secret_repositories.rb b/db/migrate/20190909061930_create_shixun_secret_repositories.rb new file mode 100644 index 000000000..5526869f8 --- /dev/null +++ b/db/migrate/20190909061930_create_shixun_secret_repositories.rb @@ -0,0 +1,10 @@ +class CreateShixunSecretRepositories < ActiveRecord::Migration[5.2] + def change + create_table :shixun_secret_repositories do |t| + t.references :shixun + t.string :repo_name + t.string :secret_dir_path + t.timestamps + end + end +end diff --git a/db/migrate/20190909072626_add_match_rule_for_test_sets.rb b/db/migrate/20190909072626_add_match_rule_for_test_sets.rb new file mode 100644 index 000000000..2d9d53f0f --- /dev/null +++ b/db/migrate/20190909072626_add_match_rule_for_test_sets.rb @@ -0,0 +1,7 @@ +class AddMatchRuleForTestSets < ActiveRecord::Migration[5.2] + def change + add_column :test_sets, :match_rule, :string + TestSet.update_all(match_rule: 'full') + + end +end diff --git a/db/migrate/20190909080508_create_shixun_work_comments.rb b/db/migrate/20190909080508_create_shixun_work_comments.rb new file mode 100644 index 000000000..eb21f0d04 --- /dev/null +++ b/db/migrate/20190909080508_create_shixun_work_comments.rb @@ -0,0 +1,13 @@ +class CreateShixunWorkComments < ActiveRecord::Migration[5.2] + def change + create_table :shixun_work_comments do |t| + t.references :student_work, index: true, type: :integer + t.references :challenge, index: true, type: :integer, default: 0 + t.references :user, index: true, type: :integer + t.text :comment + t.text :hidden_comment + + t.timestamps + end + end +end diff --git a/db/migrate/20190909082555_migrate_shixun_work_comment.rb b/db/migrate/20190909082555_migrate_shixun_work_comment.rb new file mode 100644 index 000000000..f58531b80 --- /dev/null +++ b/db/migrate/20190909082555_migrate_shixun_work_comment.rb @@ -0,0 +1,13 @@ +class MigrateShixunWorkComment < ActiveRecord::Migration[5.2] + def change + StudentWorksScore.where(is_ultimate: 0, score: nil).where("created_at > '2019-09-04 00:00:00'").each do |work_score| + if work_score.student_work && work_score.student_work.homework_common&.shixuns + if work_score.is_hidden + ShixunWorkComment.create!(student_work_id: work_score.student_work_id, user_id: work_score.user_id, hidden_comment: work_score.comment) + else + ShixunWorkComment.create!(student_work_id: work_score.student_work_id, user_id: work_score.user_id, comment: work_score.comment) + end + end + end + end +end diff --git a/db/migrate/20190910061807_create_course_stages.rb b/db/migrate/20190910061807_create_course_stages.rb new file mode 100644 index 000000000..c664b7f92 --- /dev/null +++ b/db/migrate/20190910061807_create_course_stages.rb @@ -0,0 +1,13 @@ +class CreateCourseStages < ActiveRecord::Migration[5.2] + def change + create_table :course_stages do |t| + t.references :course, index: true + t.string :name + t.text :description + t.integer :position + t.integer :shixuns_count + + t.timestamps + end + end +end diff --git a/db/migrate/20190910062710_create_course_stage_shixuns.rb b/db/migrate/20190910062710_create_course_stage_shixuns.rb new file mode 100644 index 000000000..04512c7da --- /dev/null +++ b/db/migrate/20190910062710_create_course_stage_shixuns.rb @@ -0,0 +1,12 @@ +class CreateCourseStageShixuns < ActiveRecord::Migration[5.2] + def change + create_table :course_stage_shixuns do |t| + t.references :course, index: true + t.references :course_stage, index: true + t.references :shixun, index: true + t.integer :position + + t.timestamps + end + end +end diff --git a/db/migrate/20190910063345_migrate_course_stages.rb b/db/migrate/20190910063345_migrate_course_stages.rb new file mode 100644 index 000000000..0aae05103 --- /dev/null +++ b/db/migrate/20190910063345_migrate_course_stages.rb @@ -0,0 +1,14 @@ +class MigrateCourseStages < ActiveRecord::Migration[5.2] + def change + Course.where(excellent: 1).each do |course| + if course.subject + course.subject.stages.each do |stage| + new_stage = CourseStage.create!(course_id: course.id, name: stage.name, description: stage.description, position: stage.position) + stage.stage_shixuns.each do |stage_shixun| + CourseStageShixun.create!(course_id: course.id, course_stage_id: new_stage.id, shixun_id: stage_shixun.shixun_id, position: stage_shixun.position) + end + end + end + end + end +end diff --git a/db/migrate/20190911020749_migrate_shixun_student_work.rb b/db/migrate/20190911020749_migrate_shixun_student_work.rb new file mode 100644 index 000000000..54474c544 --- /dev/null +++ b/db/migrate/20190911020749_migrate_shixun_student_work.rb @@ -0,0 +1,18 @@ +class MigrateShixunStudentWork < ActiveRecord::Migration[5.2] + def change + homework_commons = HomeworkCommon.where(homework_type: 4).where("created_at > '2019-07-01 00:00:00'") + attrs = %i[homework_common_id user_id created_at updated_at] + StudentWork.bulk_insert(*attrs) do |worker| + homework_commons.each do |homework| + course = homework.course + if course && homework.student_works.count != course.students.count + course.students.each do |student| + next if StudentWork.where(homework_common_id: homework.id, user_id: student.user_id).any? + same_attrs = {user_id: student.user_id} + worker.add same_attrs.merge(homework_common_id: homework.id) + end + end + end + end + end +end diff --git a/db/migrate/20190911074019_add_code_edit_permission_for_shixun.rb b/db/migrate/20190911074019_add_code_edit_permission_for_shixun.rb new file mode 100644 index 000000000..801713e0e --- /dev/null +++ b/db/migrate/20190911074019_add_code_edit_permission_for_shixun.rb @@ -0,0 +1,6 @@ +class AddCodeEditPermissionForShixun < ActiveRecord::Migration[5.2] + def change + + add_column :shixuns, :code_edit_permission, :boolean, default: false + end +end diff --git a/db/migrate/20190911103449_migrate_grade_index.rb b/db/migrate/20190911103449_migrate_grade_index.rb new file mode 100644 index 000000000..0128619fa --- /dev/null +++ b/db/migrate/20190911103449_migrate_grade_index.rb @@ -0,0 +1,7 @@ +class MigrateGradeIndex < ActiveRecord::Migration[5.2] + def change + remove_index :grades, [:user_id, :container_id] + add_index :grades, [:container_id, :container_type] + add_index :grades, [:user_id] + end +end diff --git a/dump.rdb b/dump.rdb index bcf064366..9f62f75c7 100644 Binary files a/dump.rdb and b/dump.rdb differ diff --git a/lib/tasks/excellent_course_exercise.rake b/lib/tasks/excellent_course_exercise.rake index 4309eec26..e05a813f4 100644 --- a/lib/tasks/excellent_course_exercise.rake +++ b/lib/tasks/excellent_course_exercise.rake @@ -14,7 +14,7 @@ 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) @@ -26,7 +26,7 @@ namespace :excellent_course_exercise do members = course.students.order("id asc").limit(new_participant_count) update_exercise_user(exercise, members, new_pass_count) end - end + # end end end diff --git a/lib/tasks/public_course_sync.rake b/lib/tasks/public_course_sync.rake index 928cd9113..c26090e81 100644 --- a/lib/tasks/public_course_sync.rake +++ b/lib/tasks/public_course_sync.rake @@ -1,5 +1,5 @@ #coding=utf-8 -# 执行示例 bundle exec rake public_course:student args=149,2903 +# 执行示例 RAILS_ENV=production bundle exec rake public_classes:student args=3,3056,'2019-03-01','2019-03-31',10,1 # args 第一个参数是subject_id,第二个参数是课程course_id # 第一期时间:2018-12-16 至2019-03-31 # 第二期时间:2019-04-07 至2019-07-28 @@ -22,10 +22,13 @@ namespace :public_classes do task :student => :environment do puts "subject_id is #{subject_id}" puts "course_id is #{course_id}" + puts "start time is #{start_time}" + puts "end time is #{end_time}" + puts "limt is #{limit}" - user_ids = Myshixun.find_by_sql("select distinct(user_id) from myshixuns where created_at between #{start_time} and #{end_time} and shixun_id in (select shixun_id from stage_shixuns + user_ids = Myshixun.find_by_sql("select distinct(user_id) from myshixuns where created_at between '#{start_time}' and '#{end_time}' and shixun_id in (select shixun_id from stage_shixuns where stage_id in (select id from stages where subject_id=#{subject_id})) limit #{limit}").map(&:user_id) - puts user_ids + puts "user_ids count is #{user_ids.count}" if user_ids.present? user_ids.each do |user_id| puts user_id @@ -39,8 +42,8 @@ namespace :public_classes do end task :test_user => :environment do - users = User.where(is_test: true) - users.limit(limit).find_each do |user| + users = User.where(is_test: true).limit(limit) + users.find_each do |user| puts user.id CourseMember.create!(course_id: course_id, user_id: user.id, role: 4) end @@ -78,8 +81,10 @@ namespace :public_classes do homework.update_columns(publish_time: publish_time, end_time: end_time, created_at: created_at, updated_at: updated_at) homework.homework_detail_manual.update_columns(comment_status: 6, created_at: created_at, updated_at: updated_at) + homework.update_homework_work_score + homework.update_attribute('calculation_time', end_time) - homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) + # homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) end when 3 # 试卷 diff --git a/lib/tasks/public_message.rake b/lib/tasks/public_message.rake index 9b2f89224..e51917a2e 100644 --- a/lib/tasks/public_message.rake +++ b/lib/tasks/public_message.rake @@ -1,30 +1,22 @@ -# bundle exec rake sync:public_message args=149,2903 +# RAILS_ENV=production bundle exec rake sync:sigle_message args=3,-1,8848,48337,'2017-07-23','2017-10-31',1000 namespace :sync do - task :public_message => :environment do + if ENV['args'] subject_id = ENV['args'].split(",")[0] # 对应课程的id shixun_id = ENV['args'].split(",")[1] # 对应课程的id board_id = ENV['args'].split(",")[2] message_id = ENV['args'].split(",")[3] - status = ENV['args'].split(",")[4] # 表示相应的期数 - - if status.to_i == 1 - start_time = '2018-12-16' - end_time = '2019-04-01' - elsif status.to_i == 2 - start_time = '2019-04-07' - end_time = '2019-07-28' - else - # 这种情况是取所有的 - start_time = '2015-01-01' - end_time = '2022-07-28' - end + start_time = ENV['args'].split(",")[4] # 表示课程模块 + end_time = ENV['args'].split(",")[5] # 表示课程模块 + limit = ENV['args'].split(",")[6] # 限制导入的数量 + end + task :public_message => :environment do shixun_ids = Shixun.find_by_sql("select shixun_id from stage_shixuns where stage_id in (select id from stages where subject_id=#{subject_id}) ").map(&:shixun_id) discusses = Discuss.where(dis_id: shixun_ids).where("created_at >? and created_at :environment do - subject_id = ENV['args'].split(",")[0] # 对应课程的id - shixun_id = ENV['args'].split(",")[1] # 对应课程的id - board_id = ENV['args'].split(",")[2] - message_id = ENV['args'].split(",")[3] - status = ENV['args'].split(",")[4] # 表示相应的期数 - - if status.to_i == 1 - start_time = '2018-12-16' - end_time = '2019-04-01' - elsif status.to_i == 2 - start_time = '2019-04-07' - end_time = '2019-07-28' - else - # 这种情况是取所有的 - start_time = '2015-01-01' - end_time = '2022-07-28' - end if subject_id.to_i == -1 discusses = Discuss.where("parent_id is null and dis_id=?", shixun_id) else shixun_ids = Shixun.find_by_sql("select shixun_id from stage_shixuns where stage_id in (select id from stages where subject_id=#{subject_id}) ").map(&:shixun_id) - discusses = Discuss.where("parent_id is null").where(dis_id: shixun_ids) + discusses = Discuss.where("parent_id is null and created_at between '#{start_time}' and '#{end_time}'").where(dis_id: shixun_ids) end discusses.each do |discuss| @@ -119,18 +94,8 @@ namespace :sync do end end - task :board_count => :environment do - Course.find_each do |course| - puts course.id - - begin - messages_count = Message.find_by_sql("select count(*) as count from messages where board_id in (select id from boards where course_id=#{course.id})").first.try(:count) - - Board.update_column(messages_count: messages_count) - rescue - - end - - end + task :delete_boards => :environment do + course = Course.find(course_id) + course.boards.destroy end end diff --git a/lib/tasks/user_login.rake b/lib/tasks/user_login.rake new file mode 100644 index 000000000..31dfbb2b4 --- /dev/null +++ b/lib/tasks/user_login.rake @@ -0,0 +1,28 @@ +namespace :user do + task :update_login => :environment do + begin + user_count = ENV['args'].split(",")[0].to_i # 更新的用户数 + status = ENV['args'].split(",")[1] # 测试用户类型 + base_login = ENV['args'].split(",")[2] # 基本的用户参数 + + users = User.where(:is_test => status).limit(user_count) + users.each_with_index do |user, i| + puts i + + no = sprintf("%04d", i) + login = "#{base_login}#{no}" + puts no + puts login + + sql1 = "update users set login='#{login}' where id=#{user.id}" + sql2 = "update users set lastname='#{login}' where id=#{user.id}" + sql3 = "update users set nickname='#{login}' where id=#{user.id}" + ActiveRecord::Base.connection.execute(sql1) + ActiveRecord::Base.connection.execute(sql2) + ActiveRecord::Base.connection.execute(sql3) + end + rescue Exception => e + Rails.logger.error(e.message) + end + end +end \ No newline at end of file diff --git a/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json new file mode 100644 index 000000000..c01010b9b --- /dev/null +++ b/public/assets/.sprockets-manifest-4627fa5586ef7fed55ca286af7c028e9.json @@ -0,0 +1 @@ +{"files":{"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js":{"logical_path":"admin.js","mtime":"2019-09-11T16:20:07+08:00","size":4350881,"digest":"cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121","integrity":"sha256-zZyousyXPOLbrOMMl/bEC8COLC7kSXL2aOc44ZAsASE="},"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css":{"logical_path":"admin.css","mtime":"2019-09-11T16:20:07+08:00","size":773445,"digest":"a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa","integrity":"sha256-obM1bv5Q/0cXzyJHVjm1MzxTVLoD/RB8m3qNSudvR6o="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-23T09:13:14+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-23T09:13:14+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-23T09:13:14+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-23T09:13:14+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-23T09:13:14+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-09-11T16:20:07+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css":{"logical_path":"college.css","mtime":"2019-09-11T16:20:07+08:00","size":546841,"digest":"944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9","integrity":"sha256-lE1Cc/YsdTg2i5AX/dM4e1476jGoeHN3DrIxMkVG1Nk="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-08-23T10:44:25+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-09-11T16:20:07+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css":{"logical_path":"application.css","mtime":"2019-09-11T16:20:07+08:00","size":1844002,"digest":"5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2","integrity":"sha256-Xrh8bhNnbQGDMX3rzhf63ifmjErO4oxBlDjaFdU8lPI="}},"assets":{"admin.js":"admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js","admin.css":"admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-944d4273f62c7538368b9017fdd3387b5e3bea31a87873770eb231324546d4d9.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-5eb87c6e13676d0183317debce17fade27e68c4acee28c419438da15d53c94f2.css"}} \ No newline at end of file diff --git a/public/assets/.sprockets-manifest-fd1f19755cf79ae07a20ee9d2676d85e.json b/public/assets/.sprockets-manifest-fd1f19755cf79ae07a20ee9d2676d85e.json deleted file mode 100644 index 984d53e13..000000000 --- a/public/assets/.sprockets-manifest-fd1f19755cf79ae07a20ee9d2676d85e.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"admin-81f6ac4c1ad5e53b10117d319ac4a62d8b76f65baf7b06fdedc47323635bcdaf.js":{"logical_path":"admin.js","mtime":"2019-08-31T16:52:07+08:00","size":4098146,"digest":"81f6ac4c1ad5e53b10117d319ac4a62d8b76f65baf7b06fdedc47323635bcdaf","integrity":"sha256-gfasTBrV5TsQEX0xmsSmLYt29luvewb97cRzI2Nbza8="},"admin-07f89a76946f8ce796dafa51fbda5443521854cd6fe7eecf750cf443f1e699c9.css":{"logical_path":"admin.css","mtime":"2019-08-31T16:52:07+08:00","size":642497,"digest":"07f89a76946f8ce796dafa51fbda5443521854cd6fe7eecf750cf443f1e699c9","integrity":"sha256-B/iadpRvjOeW2vpR+9pUQ1IYVM1v5+7PdQz0Q/Hmmck="},"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot":{"logical_path":"font-awesome/fontawesome-webfont.eot","mtime":"2019-08-23T09:13:14+08:00","size":165742,"digest":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","integrity":"sha256-e/yrbbmdXPvxcFygU23ceFhUMsxfpBu9etDwCQM7KXk="},"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2":{"logical_path":"font-awesome/fontawesome-webfont.woff2","mtime":"2019-08-23T09:13:14+08:00","size":77160,"digest":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","integrity":"sha256-Kt78vAQefRj88tQXh53FoJmXqmTWdbejxLbOM9oT8/4="},"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff":{"logical_path":"font-awesome/fontawesome-webfont.woff","mtime":"2019-08-23T09:13:14+08:00","size":98024,"digest":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","integrity":"sha256-ugxZ3rVFD1y0Gz+TYJ7i0NmVQVh33foiPoqKdTNHTwc="},"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf":{"logical_path":"font-awesome/fontawesome-webfont.ttf","mtime":"2019-08-23T09:13:14+08:00","size":165548,"digest":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","integrity":"sha256-qljzPyOaD7AvXHpsRcBD16msmgkzNYBmlOzW1O3A1qg="},"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg":{"logical_path":"font-awesome/fontawesome-webfont.svg","mtime":"2019-08-23T09:13:14+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-09-03T09:32:01+08:00","size":3352744,"digest":"18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287","integrity":"sha256-GPXoQAMxY06JijWswhh4FcCWwl4Kt0q6NBrpFhZs0oc="},"college-279b722d063f61aec89f1ad6f44c4a620f522278a4668cc218465ad8f539966f.css":{"logical_path":"college.css","mtime":"2019-08-30T17:20:58+08:00","size":545696,"digest":"279b722d063f61aec89f1ad6f44c4a620f522278a4668cc218465ad8f539966f","integrity":"sha256-J5tyLQY/Ya7InxrW9ExKYg9SInikZozCGEZa2PU5lm8="},"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png":{"logical_path":"logo.png","mtime":"2019-08-23T10:44:25+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-830ab01de7cd41145be3bd392304541807c3ea985eb566bdabdbafee7f6c6735.js":{"logical_path":"application.js","mtime":"2019-08-31T16:52:07+08:00","size":4237790,"digest":"830ab01de7cd41145be3bd392304541807c3ea985eb566bdabdbafee7f6c6735","integrity":"sha256-gwqwHefNQRRb4705IwRUGAfD6phetWa9q9uv7n9sZzU="},"application-1bce1740cf43111049b991ad4d5537a46deb578488e47bbb006d551b54f72895.css":{"logical_path":"application.css","mtime":"2019-08-31T16:52:07+08:00","size":1702694,"digest":"1bce1740cf43111049b991ad4d5537a46deb578488e47bbb006d551b54f72895","integrity":"sha256-G84XQM9DERBJuZGtTVU3pG3rV4SI5Hu7AG1VG1T3KJU="},"admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js":{"logical_path":"admin.js","mtime":"2019-09-02T13:59:22+08:00","size":4108754,"digest":"73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674","integrity":"sha256-c8cO097V2odrwp+fsexffVYbBocwo6jq2bPmrMY8pnQ="},"admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css":{"logical_path":"admin.css","mtime":"2019-09-02T11:16:43+08:00","size":677443,"digest":"521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef","integrity":"sha256-Uhhiydow7MI3RbcNcpCiOrLob9856JofwsJkLBag1+8="},"college-315d626b40fca41ae2670fb1700bfed6093f1ad56a3cc3cef00be02faedb0176.css":{"logical_path":"college.css","mtime":"2019-08-30T14:31:33+08:00","size":577964,"digest":"315d626b40fca41ae2670fb1700bfed6093f1ad56a3cc3cef00be02faedb0176","integrity":"sha256-MV1ia0D8pBriZw+xcAv+1gk/GtVqPMPO8AvgL67bAXY="},"application-a2d0caa2bacf00e70e216c9accf36a58f748652cb3b0cde2153fbaa9cfcecd15.js":{"logical_path":"application.js","mtime":"2019-09-02T13:59:22+08:00","size":4248398,"digest":"a2d0caa2bacf00e70e216c9accf36a58f748652cb3b0cde2153fbaa9cfcecd15","integrity":"sha256-otDKorrPAOcOIWyazPNqWPdIZSyzsM3iFT+6qc/OzRU="},"application-b12c6a987e49d1cda015d172244bc61badb8dd37ea38b74d864ba5d14b201d71.css":{"logical_path":"application.css","mtime":"2019-09-02T11:16:43+08:00","size":1796351,"digest":"b12c6a987e49d1cda015d172244bc61badb8dd37ea38b74d864ba5d14b201d71","integrity":"sha256-sSxqmH5J0c2gFdFyJEvGG6243TfqOLdNhkul0UsgHXE="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-09-03T09:32:01+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="},"admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js":{"logical_path":"admin.js","mtime":"2019-09-03T16:33:00+08:00","size":4109893,"digest":"4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626","integrity":"sha256-SoiE8gWsIdwhYUy0wKeAfiQS/gFniLB1UJ/hR90rpiY="},"admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css":{"logical_path":"admin.css","mtime":"2019-09-03T09:11:24+08:00","size":645175,"digest":"b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc","integrity":"sha256-t0+vAIosxMPCUBtSMo9r+IaETC3wJwJULuvB0gvL8bw="},"application-c211e6e621d2af392dceb6ca165bc4f48889e815e259792ca352d17f52362f6b.css":{"logical_path":"application.css","mtime":"2019-09-03T09:11:24+08:00","size":1708067,"digest":"c211e6e621d2af392dceb6ca165bc4f48889e815e259792ca352d17f52362f6b","integrity":"sha256-whHm5iHSrzktzrbKFlvE9IiJ6BXiWXkso1LRf1I2L2s="}},"assets":{"admin.js":"admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js","admin.css":"admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css","font-awesome/fontawesome-webfont.eot":"font-awesome/fontawesome-webfont-7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979.eot","font-awesome/fontawesome-webfont.woff2":"font-awesome/fontawesome-webfont-2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe.woff2","font-awesome/fontawesome-webfont.woff":"font-awesome/fontawesome-webfont-ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07.woff","font-awesome/fontawesome-webfont.ttf":"font-awesome/fontawesome-webfont-aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8.ttf","font-awesome/fontawesome-webfont.svg":"font-awesome/fontawesome-webfont-ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4.svg","college.js":"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js","college.css":"college-279b722d063f61aec89f1ad6f44c4a620f522278a4668cc218465ad8f539966f.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-c211e6e621d2af392dceb6ca165bc4f48889e815e259792ca352d17f52362f6b.css"}} \ No newline at end of file diff --git a/public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js.gz b/public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js.gz deleted file mode 100644 index 56d0c68ca..000000000 Binary files a/public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js.gz and /dev/null differ diff --git a/public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css b/public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css similarity index 83% rename from public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css rename to public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css index 82aa2d21b..50f786fe9 100644 --- a/public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css +++ b/public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css @@ -18537,6 +18537,4982 @@ span.CodeMirror-selectedtext { background: none; } +/*! Editor.md v1.5.0 | editormd.min.css | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ +/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.fa-ul, .markdown-body .task-list-item, li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 { + list-style-type: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form br, .markdown-body hr:after { + clear: both; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd { + width: 90%; + height: 640px; + margin: 0 auto 15px; + text-align: left; + overflow: hidden; + position: relative; + border: 1px solid #ddd; + font-family: "Meiryo UI","Microsoft YaHei","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,monospace,Tahoma,STXihei,"华文细黑",STHeiti,"Helvetica Neue","Droid Sans","wenquanyi micro hei",FreeSans,Arimo,Arial,SimSun,"宋体",Heiti,"黑体",sans-serif; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd *, .editormd :after, .editormd :before { + box-sizing: border-box; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd a { + text-decoration: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd img { + border: none; + vertical-align: middle; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .editormd-html-textarea, .editormd .editormd-markdown-textarea, .editormd > textarea { + width: 0; + height: 0; + outline: 0; + resize: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .editormd-html-textarea, .editormd .editormd-markdown-textarea { + display: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd button, .editormd input[type=text], .editormd input[type=button], .editormd input[type=submit], .editormd select, .editormd textarea { + -webkit-appearance: none; + -moz-appearance: none; + -ms-appearance: none; + appearance: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd ::-webkit-scrollbar { + height: 10px; + width: 7px; + background: rgba(0, 0, 0, 0.1); +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd ::-webkit-scrollbar:hover { + background: rgba(0, 0, 0, 0.2); +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd ::-webkit-scrollbar-thumb { + background: rgba(0, 0, 0, 0.3); + border-radius: 6px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd ::-webkit-scrollbar-thumb:hover { + -ms-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25); + -o-box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25); + box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.25); + background-color: rgba(0, 0, 0, 0.4); +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-user-unselect { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-toolbar { + width: 100%; + min-height: 37px; + background: #fff; + display: none; + position: absolute; + top: 0; + left: 0; + z-index: 10; + border-bottom: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-toolbar-container { + padding: 0 8px; + min-height: 35px; + -o-user-select: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-toolbar-container, .markdown-body .octicon { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu, .markdown-body ol, .markdown-body td, .markdown-body th, .markdown-body ul { + padding: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu { + margin: 0; + list-style: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li { + margin: 0; + padding: 5px 1px; + display: inline-block; + position: relative; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li.divider { + display: inline-block; + text-indent: -9999px; + margin: 0 5px; + height: 65%; + border-right: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li > a { + outline: 0; + color: #666; + display: inline-block; + min-width: 24px; + font-size: 16px; + text-decoration: none; + text-align: center; + border-radius: 2px; + border: 1px solid #fff; + -webkit-transition: all 300ms ease-out; + transition: all 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu > li > a:hover, .editormd-menu > li > a { + -webkit-transition: all 300ms ease-out; + -moz-transition: all 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li > a.active, .editormd-menu > li > a:hover { + border: 1px solid #ddd; + background: #eee; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li > a > .fa { + text-align: center; + display: block; + padding: 5px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li > a > .editormd-bold { + padding: 5px 2px; + display: inline-block; + font-weight: 700; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li:hover .editormd-dropdown-menu { + display: block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-menu > li + li > a { + margin-left: 3px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu { + display: none; + background: #fff; + border: 1px solid #ddd; + width: 148px; + list-style: none; + position: absolute; + top: 33px; + left: 0; + z-index: 100; + -ms-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15); + -o-box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15); + box-shadow: 1px 2px 6px rgba(0, 0, 0, 0.15); +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu:after, .editormd-dropdown-menu:before { + width: 0; + height: 0; + display: block; + content: ""; + position: absolute; + top: -11px; + left: 8px; + border: 5px solid transparent; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu:before { + border-bottom-color: #ccc; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu:after { + border-bottom-color: #fff; + top: -10px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu > li > a { + color: #666; + display: block; + text-decoration: none; + padding: 8px 10px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu > li > a:hover { + background: #f6f6f6; + -webkit-transition: all 300ms ease-out; + transition: all 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dropdown-menu > li + li { + border-top: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-container { + margin: 0; + width: 100%; + height: 100%; + overflow: hidden; + padding: 35px 0 0; + position: relative; + background: #fff; + box-sizing: border-box; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog { + color: #666; + position: fixed; + z-index: 99999; + display: none; + border-radius: 3px; + -ms-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + -o-box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + background: #fff; + font-size: 14px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container { + position: relative; + padding: 20px; + line-height: 1.4; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container h1 { + font-size: 24px; + margin-bottom: 10px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container h1 .fa { + color: #2C7EEA; + padding-right: 5px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container h1 small { + padding-left: 5px; + font-weight: 400; + font-size: 12px; + color: #999; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container select { + color: #999; + padding: 3px 8px; + border: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-close { + position: absolute; + top: 12px; + right: 15px; + font-size: 18px; + color: #ccc; + -webkit-transition: color 300ms ease-out; + transition: color 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-close:hover { + color: #999; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-header { + padding: 11px 20px; + border-bottom: 1px solid #eee; + -webkit-transition: background 300ms ease-out; + transition: background 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-header:hover { + background: #f6f6f6; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-title { + font-size: 14px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-footer { + padding: 10px 0 0; + text-align: right; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info { + width: 420px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info h1 { + font-weight: 400; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info .editormd-dialog-container { + padding: 20px 25px 25px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info .editormd-dialog-close { + top: 10px; + right: 10px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info .hover-link:hover, .editormd-dialog-info p > a { + color: #2196F3; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info .hover-link { + color: #666; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info a .fa-external-link { + display: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info a:hover { + color: #2196F3; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-info a:hover .fa-external-link { + display: inline-block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-container-mask, .editormd-dialog-mask, .editormd-mask { + display: none; + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-mask-bg, .editormd-mask { + background: #fff; + opacity: .5; + filter: alpha(opacity=50); +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-mask { + position: fixed; + background: #000; + opacity: .2; + filter: alpha(opacity=20); + z-index: 99998; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-container-mask, .editormd-dialog-mask-con { + background: url(../images/loading.gif) center center no-repeat; + background-size: 32px 32px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-container-mask { + z-index: 20; + display: block; + background-color: #fff; +} + +@media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min-device-pixel-ratio: 2) { + /* line 2, vendor/assets/editormd/css/editormd.min.css */ + .editormd-container-mask, .editormd-dialog-mask-con { + background-image: url(../images/loading@2x.gif); + } +} + +@media only screen and (-webkit-min-device-pixel-ratio: 3), only screen and (min-device-pixel-ratio: 3) { + /* line 2, vendor/assets/editormd/css/editormd.min.css */ + .editormd-container-mask, .editormd-dialog-mask-con { + background-image: url(../images/loading@3x.gif); + } +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-code-block-dialog textarea, .editormd-preformatted-text-dialog textarea { + width: 100%; + height: 400px; + margin-bottom: 6px; + overflow: auto; + border: 1px solid #eee; + background: #fff; + padding: 15px; + resize: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-code-toolbar { + color: #999; + font-size: 14px; + margin: -5px 0 10px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-grid-table { + width: 99%; + display: table; + border: 1px solid #ddd; + border-collapse: collapse; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-grid-table-row { + width: 100%; + display: table-row; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-grid-table-row a { + font-size: 1.4em; + width: 5%; + height: 36px; + color: #999; + text-align: center; + display: table-cell; + vertical-align: middle; + border: 1px solid #ddd; + text-decoration: none; + -webkit-transition: background-color 300ms ease-out,color 100ms ease-in; + transition: background-color 300ms ease-out,color 100ms ease-in; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-grid-table-row a.selected { + color: #666; + background-color: #eee; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-grid-table-row a:hover { + color: #777; + background-color: #f6f6f6; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head { + list-style: none; + border-bottom: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head li { + display: inline-block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head li a { + color: #999; + display: block; + padding: 6px 12px 5px; + text-align: center; + text-decoration: none; + margin-bottom: -1px; + border: 1px solid #ddd; + -moz-border-top-left-radius: 3px; + border-top-left-radius: 3px; + -moz-border-top-right-radius: 3px; + border-top-right-radius: 3px; + background: #f6f6f6; + -webkit-transition: all 300ms ease-out; + transition: all 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head li a:hover { + color: #666; + background: #eee; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head li.active a { + color: #666; + background: #fff; + border-bottom-color: #fff; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-head li + li { + margin-left: 3px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-tab-box { + padding: 20px 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form { + color: #666; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form label { + float: left; + display: block; + width: 75px; + text-align: left; + padding: 7px 0 15px 5px; + margin: 0 0 2px; + font-weight: 400; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form iframe { + display: none; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form input:focus { + outline: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form input[type=text], .editormd-form input[type=number] { + color: #999; + padding: 8px; + border: 1px solid #ddd; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form input[type=number] { + width: 40px; + display: inline-block; + padding: 6px 8px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form input[type=text] { + display: inline-block; + width: 264px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form .fa-btns { + display: inline-block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form .fa-btns a { + color: #999; + padding: 7px 10px 0 0; + display: inline-block; + text-decoration: none; + text-align: center; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form .fa-btns .fa { + font-size: 1.3em; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-form .fa-btns label { + float: none; + display: inline-block; + width: auto; + text-align: left; + padding: 0 0 0 5px; + cursor: pointer; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.fa-fw, .fa-li { + text-align: center; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container .editormd-btn, .editormd-dialog-container button, .editormd-dialog-container input[type=submit], .editormd-dialog-footer .editormd-btn, .editormd-dialog-footer button, .editormd-dialog-footer input[type=submit], .editormd-form .editormd-btn, .editormd-form button, .editormd-form input[type=submit] { + color: #666; + min-width: 75px; + cursor: pointer; + background: #fff; + padding: 7px 10px; + border: 1px solid #ddd; + border-radius: 3px; + -webkit-transition: background 300ms ease-out; + transition: background 300ms ease-out; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container .editormd-btn:hover, .editormd-dialog-container button:hover, .editormd-dialog-container input[type=submit]:hover, .editormd-dialog-footer .editormd-btn:hover, .editormd-dialog-footer button:hover, .editormd-dialog-footer input[type=submit]:hover, .editormd-form .editormd-btn:hover, .editormd-form button:hover, .editormd-form input[type=submit]:hover { + background: #eee; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-dialog-container .editormd-btn + .editormd-btn, .editormd-dialog-footer .editormd-btn + .editormd-btn, .editormd-form .editormd-btn + .editormd-btn { + margin-left: 8px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-file-input { + width: 75px; + height: 32px; + margin-left: 8px; + position: relative; + display: inline-block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-file-input input[type=file] { + width: 75px; + height: 32px; + opacity: 0; + cursor: pointer; + background: #000; + display: inline-block; + position: absolute; + top: 0; + right: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-file-input input[type=file]::-webkit-file-upload-button { + visibility: hidden; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-file-input:hover input[type=submit] { + background: #eee; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror, .editormd-preview { + display: inline-block; + width: 50%; + height: 100%; + vertical-align: top; + box-sizing: border-box; + margin: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview { + position: absolute; + top: 35px; + right: 0; + overflow: auto; + line-height: 1.6; + display: none; + background: #fff; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.fa, .fa-stack { + display: inline-block; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror { + z-index: 10; + float: left; + border-right: 1px solid #ddd; + font-size: 14px; + font-family: "YaHei Consolas Hybrid",Consolas,"微软雅黑","Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,courier,monospace; + line-height: 1.6; + margin-top: 35px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror pre { + font-size: 14px; + padding: 0 12px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror-linenumbers { + padding: 0 5px; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror-focused .CodeMirror-selected, .editormd .CodeMirror-selected { + background: #70B7FF; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror, .editormd .CodeMirror-scroll, .editormd .editormd-preview { + -webkit-overflow-scrolling: touch; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .styled-background { + background-color: #ff7; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror-focused .cm-matchhighlight { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==); + background-position: bottom; + background-repeat: repeat-x; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror-empty.CodeMirror-focused { + outline: 0; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .CodeMirror pre.CodeMirror-placeholder { + color: #999; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .cm-trailingspace { + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==); + background-position: bottom left; + background-repeat: repeat-x; +} + +/* line 2, vendor/assets/editormd/css/editormd.min.css */ +.editormd .cm-tab { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=) right no-repeat; +} + +/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ +/*! + * Font Awesome 4.3.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +@font-face { + font-family: FontAwesome; + src: url(../fonts/fontawesome-webfont.eot?v=4.3.0); + src: url(../fonts/fontawesome-webfont.eot?#iefix&v=4.3.0) format("embedded-opentype"), url(../fonts/fontawesome-webfont.woff2?v=4.3.0) format("woff2"), url(../fonts/fontawesome-webfont.woff?v=4.3.0) format("woff"), url(../fonts/fontawesome-webfont.ttf?v=4.3.0) format("truetype"), url(../fonts/fontawesome-webfont.svg?v=4.3.0#fontawesomeregular) format("svg"); + font-weight: 400; + font-style: normal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa { + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-transform: translate(0, 0); + transform: translate(0, 0); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lg { + font-size: 1.33333333em; + line-height: .75em; + vertical-align: -15%; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-2x { + font-size: 2em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-3x { + font-size: 3em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-4x { + font-size: 4em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-5x { + font-size: 5em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fw { + width: 1.28571429em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ul > li { + position: relative; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: .14285714em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-li.fa-lg { + left: -1.85714286em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-border { + padding: .2em .25em .15em; + border: .08em solid #eee; + border-radius: .1em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.pull-right { + float: right; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.pull-left { + float: left; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa.pull-left { + margin-right: .3em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa.pull-right { + margin-left: .3em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0); + transform: rotate(0); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + transform: rotate(270deg); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flip-horizontal { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1); + -webkit-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flip-vertical { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1); + -webkit-transform: scale(1, -1); + transform: scale(1, -1); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +:root .fa-flip-horizontal, :root .fa-flip-vertical, :root .fa-rotate-180, :root .fa-rotate-270, :root .fa-rotate-90 { + -webkit-filter: none; + filter: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack { + position: relative; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack-1x, .fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack-1x { + line-height: inherit; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack-2x { + font-size: 2em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-inverse { + color: #fff; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-glass:before { + content: "\f000"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-music:before { + content: "\f001"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-search:before { + content: "\f002"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-envelope-o:before { + content: "\f003"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-heart:before { + content: "\f004"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-star:before { + content: "\f005"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-star-o:before { + content: "\f006"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-user:before { + content: "\f007"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-film:before { + content: "\f008"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-th-large:before { + content: "\f009"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-th:before { + content: "\f00a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-th-list:before { + content: "\f00b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-check:before { + content: "\f00c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-close:before, .fa-remove:before, .fa-times:before { + content: "\f00d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-search-plus:before { + content: "\f00e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-search-minus:before { + content: "\f010"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-power-off:before { + content: "\f011"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-signal:before { + content: "\f012"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cog:before, .fa-gear:before { + content: "\f013"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-trash-o:before { + content: "\f014"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-home:before { + content: "\f015"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-o:before { + content: "\f016"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-clock-o:before { + content: "\f017"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-road:before { + content: "\f018"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-download:before { + content: "\f019"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-o-down:before { + content: "\f01a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-o-up:before { + content: "\f01b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-inbox:before { + content: "\f01c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-play-circle-o:before { + content: "\f01d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-repeat:before, .fa-rotate-right:before { + content: "\f01e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-refresh:before { + content: "\f021"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-list-alt:before { + content: "\f022"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lock:before { + content: "\f023"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flag:before { + content: "\f024"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-headphones:before { + content: "\f025"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-volume-off:before { + content: "\f026"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-volume-down:before { + content: "\f027"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-volume-up:before { + content: "\f028"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-qrcode:before { + content: "\f029"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-barcode:before { + content: "\f02a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tag:before { + content: "\f02b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tags:before { + content: "\f02c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-book:before { + content: "\f02d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bookmark:before { + content: "\f02e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-print:before { + content: "\f02f"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-camera:before { + content: "\f030"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-font:before { + content: "\f031"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bold:before { + content: "\f032"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-italic:before { + content: "\f033"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-text-height:before { + content: "\f034"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-text-width:before { + content: "\f035"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-align-left:before { + content: "\f036"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-align-center:before { + content: "\f037"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-align-right:before { + content: "\f038"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-align-justify:before { + content: "\f039"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-list:before { + content: "\f03a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dedent:before, +.fa-outdent:before { + content: "\f03b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-indent:before { + content: "\f03c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-video-camera:before { + content: "\f03d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-image:before, .fa-photo:before, .fa-picture-o:before { + content: "\f03e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pencil:before { + content: "\f040"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-map-marker:before { + content: "\f041"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-adjust:before { + content: "\f042"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tint:before { + content: "\f043"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-edit:before, +.fa-pencil-square-o:before { + content: "\f044"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-share-square-o:before { + content: "\f045"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-check-square-o:before { + content: "\f046"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrows:before { + content: "\f047"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-step-backward:before { + content: "\f048"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fast-backward:before { + content: "\f049"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-backward:before { + content: "\f04a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-play:before { + content: "\f04b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pause:before { + content: "\f04c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stop:before { + content: "\f04d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-forward:before { + content: "\f04e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fast-forward:before { + content: "\f050"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-step-forward:before { + content: "\f051"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eject:before { + content: "\f052"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-left:before { + content: "\f053"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-right:before { + content: "\f054"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plus-circle:before { + content: "\f055"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-minus-circle:before { + content: "\f056"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-times-circle:before { + content: "\f057"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-check-circle:before { + content: "\f058"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-question-circle:before { + content: "\f059"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-info-circle:before { + content: "\f05a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-crosshairs:before { + content: "\f05b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-times-circle-o:before { + content: "\f05c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-check-circle-o:before { + content: "\f05d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ban:before { + content: "\f05e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-left:before { + content: "\f060"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-right:before { + content: "\f061"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-up:before { + content: "\f062"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-down:before { + content: "\f063"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mail-forward:before, +.fa-share:before { + content: "\f064"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-expand:before { + content: "\f065"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-compress:before { + content: "\f066"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plus:before { + content: "\f067"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-minus:before { + content: "\f068"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-asterisk:before { + content: "\f069"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-exclamation-circle:before { + content: "\f06a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-gift:before { + content: "\f06b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-leaf:before { + content: "\f06c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fire:before { + content: "\f06d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eye:before { + content: "\f06e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eye-slash:before { + content: "\f070"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-exclamation-triangle:before, .fa-warning:before { + content: "\f071"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plane:before { + content: "\f072"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-calendar:before { + content: "\f073"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-random:before { + content: "\f074"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-comment:before { + content: "\f075"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-magnet:before { + content: "\f076"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-up:before { + content: "\f077"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-down:before { + content: "\f078"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-retweet:before { + content: "\f079"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-shopping-cart:before { + content: "\f07a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-folder:before { + content: "\f07b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-folder-open:before { + content: "\f07c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrows-v:before { + content: "\f07d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrows-h:before { + content: "\f07e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: "\f080"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-twitter-square:before { + content: "\f081"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-facebook-square:before { + content: "\f082"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-camera-retro:before { + content: "\f083"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-key:before { + content: "\f084"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cogs:before, .fa-gears:before { + content: "\f085"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-comments:before { + content: "\f086"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-thumbs-o-up:before { + content: "\f087"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-thumbs-o-down:before { + content: "\f088"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-star-half:before { + content: "\f089"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-heart-o:before { + content: "\f08a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sign-out:before { + content: "\f08b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-linkedin-square:before { + content: "\f08c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-thumb-tack:before { + content: "\f08d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-external-link:before { + content: "\f08e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sign-in:before { + content: "\f090"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-trophy:before { + content: "\f091"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-github-square:before { + content: "\f092"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-upload:before { + content: "\f093"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lemon-o:before { + content: "\f094"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-phone:before { + content: "\f095"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-square-o:before { + content: "\f096"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bookmark-o:before { + content: "\f097"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-phone-square:before { + content: "\f098"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-twitter:before { + content: "\f099"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-facebook-f:before, +.fa-facebook:before { + content: "\f09a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-github:before { + content: "\f09b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-unlock:before { + content: "\f09c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-credit-card:before { + content: "\f09d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rss:before { + content: "\f09e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hdd-o:before { + content: "\f0a0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bullhorn:before { + content: "\f0a1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bell:before { + content: "\f0f3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-certificate:before { + content: "\f0a3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hand-o-right:before { + content: "\f0a4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hand-o-left:before { + content: "\f0a5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hand-o-up:before { + content: "\f0a6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hand-o-down:before { + content: "\f0a7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-left:before { + content: "\f0a8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-right:before { + content: "\f0a9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-up:before { + content: "\f0aa"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-down:before { + content: "\f0ab"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-globe:before { + content: "\f0ac"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-wrench:before { + content: "\f0ad"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tasks:before { + content: "\f0ae"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-filter:before { + content: "\f0b0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-briefcase:before { + content: "\f0b1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrows-alt:before { + content: "\f0b2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-group:before, +.fa-users:before { + content: "\f0c0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chain:before, +.fa-link:before { + content: "\f0c1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cloud:before { + content: "\f0c2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flask:before { + content: "\f0c3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cut:before, +.fa-scissors:before { + content: "\f0c4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-copy:before, +.fa-files-o:before { + content: "\f0c5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paperclip:before { + content: "\f0c6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-floppy-o:before, .fa-save:before { + content: "\f0c7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-square:before { + content: "\f0c8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bars:before, .fa-navicon:before, .fa-reorder:before { + content: "\f0c9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-list-ul:before { + content: "\f0ca"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-list-ol:before { + content: "\f0cb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-strikethrough:before { + content: "\f0cc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-underline:before { + content: "\f0cd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-table:before { + content: "\f0ce"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-magic:before { + content: "\f0d0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-truck:before { + content: "\f0d1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pinterest:before { + content: "\f0d2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pinterest-square:before { + content: "\f0d3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-google-plus-square:before { + content: "\f0d4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-google-plus:before { + content: "\f0d5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-money:before { + content: "\f0d6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-down:before { + content: "\f0d7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-up:before { + content: "\f0d8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-left:before { + content: "\f0d9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-right:before { + content: "\f0da"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-columns:before { + content: "\f0db"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort:before, .fa-unsorted:before { + content: "\f0dc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-desc:before, .fa-sort-down:before { + content: "\f0dd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-asc:before, .fa-sort-up:before { + content: "\f0de"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-envelope:before { + content: "\f0e0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-linkedin:before { + content: "\f0e1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rotate-left:before, +.fa-undo:before { + content: "\f0e2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-gavel:before, .fa-legal:before { + content: "\f0e3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dashboard:before, +.fa-tachometer:before { + content: "\f0e4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-comment-o:before { + content: "\f0e5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-comments-o:before { + content: "\f0e6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bolt:before, .fa-flash:before { + content: "\f0e7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sitemap:before { + content: "\f0e8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-umbrella:before { + content: "\f0e9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-clipboard:before, .fa-paste:before { + content: "\f0ea"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lightbulb-o:before { + content: "\f0eb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-exchange:before { + content: "\f0ec"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cloud-download:before { + content: "\f0ed"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cloud-upload:before { + content: "\f0ee"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-user-md:before { + content: "\f0f0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stethoscope:before { + content: "\f0f1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-suitcase:before { + content: "\f0f2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bell-o:before { + content: "\f0a2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-coffee:before { + content: "\f0f4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cutlery:before { + content: "\f0f5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-text-o:before { + content: "\f0f6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-building-o:before { + content: "\f0f7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hospital-o:before { + content: "\f0f8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ambulance:before { + content: "\f0f9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-medkit:before { + content: "\f0fa"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fighter-jet:before { + content: "\f0fb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-beer:before { + content: "\f0fc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-h-square:before { + content: "\f0fd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plus-square:before { + content: "\f0fe"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-double-left:before { + content: "\f100"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-double-right:before { + content: "\f101"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-double-up:before { + content: "\f102"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-double-down:before { + content: "\f103"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-left:before { + content: "\f104"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-right:before { + content: "\f105"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-up:before { + content: "\f106"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angle-down:before { + content: "\f107"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-desktop:before { + content: "\f108"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-laptop:before { + content: "\f109"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tablet:before { + content: "\f10a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mobile-phone:before, +.fa-mobile:before { + content: "\f10b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-circle-o:before { + content: "\f10c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-quote-left:before { + content: "\f10d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-quote-right:before { + content: "\f10e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-spinner:before { + content: "\f110"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-circle:before { + content: "\f111"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mail-reply:before, +.fa-reply:before { + content: "\f112"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-github-alt:before { + content: "\f113"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-folder-o:before { + content: "\f114"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-folder-open-o:before { + content: "\f115"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-smile-o:before { + content: "\f118"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-frown-o:before { + content: "\f119"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-meh-o:before { + content: "\f11a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-gamepad:before { + content: "\f11b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-keyboard-o:before { + content: "\f11c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flag-o:before { + content: "\f11d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flag-checkered:before { + content: "\f11e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-terminal:before { + content: "\f120"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-code:before { + content: "\f121"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: "\f122"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: "\f123"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-location-arrow:before { + content: "\f124"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-crop:before { + content: "\f125"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-code-fork:before { + content: "\f126"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chain-broken:before, .fa-unlink:before { + content: "\f127"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-question:before { + content: "\f128"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-info:before { + content: "\f129"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-exclamation:before { + content: "\f12a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-superscript:before { + content: "\f12b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-subscript:before { + content: "\f12c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eraser:before { + content: "\f12d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-puzzle-piece:before { + content: "\f12e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-microphone:before { + content: "\f130"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-microphone-slash:before { + content: "\f131"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-shield:before { + content: "\f132"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-calendar-o:before { + content: "\f133"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fire-extinguisher:before { + content: "\f134"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rocket:before { + content: "\f135"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-maxcdn:before { + content: "\f136"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-circle-left:before { + content: "\f137"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-circle-right:before { + content: "\f138"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-circle-up:before { + content: "\f139"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-chevron-circle-down:before { + content: "\f13a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-html5:before { + content: "\f13b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-css3:before { + content: "\f13c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-anchor:before { + content: "\f13d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-unlock-alt:before { + content: "\f13e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bullseye:before { + content: "\f140"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ellipsis-h:before { + content: "\f141"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ellipsis-v:before { + content: "\f142"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rss-square:before { + content: "\f143"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-play-circle:before { + content: "\f144"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ticket:before { + content: "\f145"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-minus-square:before { + content: "\f146"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-minus-square-o:before { + content: "\f147"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-level-up:before { + content: "\f148"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-level-down:before { + content: "\f149"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-check-square:before { + content: "\f14a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pencil-square:before { + content: "\f14b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-external-link-square:before { + content: "\f14c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-share-square:before { + content: "\f14d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-compass:before { + content: "\f14e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-square-o-down:before, .fa-toggle-down:before { + content: "\f150"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-square-o-up:before, .fa-toggle-up:before { + content: "\f151"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-square-o-right:before, .fa-toggle-right:before { + content: "\f152"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eur:before, .fa-euro:before { + content: "\f153"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-gbp:before { + content: "\f154"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dollar:before, +.fa-usd:before { + content: "\f155"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-inr:before, .fa-rupee:before { + content: "\f156"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cny:before, .fa-jpy:before, .fa-rmb:before, .fa-yen:before { + content: "\f157"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-rouble:before, .fa-rub:before, .fa-ruble:before { + content: "\f158"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-krw:before, .fa-won:before { + content: "\f159"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bitcoin:before, +.fa-btc:before { + content: "\f15a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file:before { + content: "\f15b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-text:before { + content: "\f15c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-alpha-asc:before { + content: "\f15d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-alpha-desc:before { + content: "\f15e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-amount-asc:before { + content: "\f160"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-amount-desc:before { + content: "\f161"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-numeric-asc:before { + content: "\f162"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sort-numeric-desc:before { + content: "\f163"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-thumbs-up:before { + content: "\f164"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-thumbs-down:before { + content: "\f165"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-youtube-square:before { + content: "\f166"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-youtube:before { + content: "\f167"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-xing:before { + content: "\f168"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-xing-square:before { + content: "\f169"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-youtube-play:before { + content: "\f16a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dropbox:before { + content: "\f16b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack-overflow:before { + content: "\f16c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-instagram:before { + content: "\f16d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-flickr:before { + content: "\f16e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-adn:before { + content: "\f170"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bitbucket:before { + content: "\f171"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bitbucket-square:before { + content: "\f172"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tumblr:before { + content: "\f173"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tumblr-square:before { + content: "\f174"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-long-arrow-down:before { + content: "\f175"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-long-arrow-up:before { + content: "\f176"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-long-arrow-left:before { + content: "\f177"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-long-arrow-right:before { + content: "\f178"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-apple:before { + content: "\f179"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-windows:before { + content: "\f17a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-android:before { + content: "\f17b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-linux:before { + content: "\f17c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dribbble:before { + content: "\f17d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-skype:before { + content: "\f17e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-foursquare:before { + content: "\f180"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-trello:before { + content: "\f181"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-female:before { + content: "\f182"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-male:before { + content: "\f183"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-gittip:before, +.fa-gratipay:before { + content: "\f184"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sun-o:before { + content: "\f185"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-moon-o:before { + content: "\f186"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-archive:before { + content: "\f187"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bug:before { + content: "\f188"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-vk:before { + content: "\f189"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-weibo:before { + content: "\f18a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-renren:before { + content: "\f18b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pagelines:before { + content: "\f18c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stack-exchange:before { + content: "\f18d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-o-right:before { + content: "\f18e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-arrow-circle-o-left:before { + content: "\f190"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-caret-square-o-left:before, .fa-toggle-left:before { + content: "\f191"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dot-circle-o:before { + content: "\f192"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-wheelchair:before { + content: "\f193"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-vimeo-square:before { + content: "\f194"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-try:before, .fa-turkish-lira:before { + content: "\f195"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plus-square-o:before { + content: "\f196"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-space-shuttle:before { + content: "\f197"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-slack:before { + content: "\f198"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-envelope-square:before { + content: "\f199"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-wordpress:before { + content: "\f19a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-openid:before { + content: "\f19b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bank:before, .fa-institution:before, .fa-university:before { + content: "\f19c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-graduation-cap:before, .fa-mortar-board:before { + content: "\f19d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-yahoo:before { + content: "\f19e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-google:before { + content: "\f1a0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-reddit:before { + content: "\f1a1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-reddit-square:before { + content: "\f1a2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stumbleupon-circle:before { + content: "\f1a3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-stumbleupon:before { + content: "\f1a4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-delicious:before { + content: "\f1a5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-digg:before { + content: "\f1a6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pied-piper:before { + content: "\f1a7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pied-piper-alt:before { + content: "\f1a8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-drupal:before { + content: "\f1a9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-joomla:before { + content: "\f1aa"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-language:before { + content: "\f1ab"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-fax:before { + content: "\f1ac"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-building:before { + content: "\f1ad"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-child:before { + content: "\f1ae"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paw:before { + content: "\f1b0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-spoon:before { + content: "\f1b1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cube:before { + content: "\f1b2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cubes:before { + content: "\f1b3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-behance:before { + content: "\f1b4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-behance-square:before { + content: "\f1b5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-steam:before { + content: "\f1b6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-steam-square:before { + content: "\f1b7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-recycle:before { + content: "\f1b8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-automobile:before, +.fa-car:before { + content: "\f1b9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cab:before, +.fa-taxi:before { + content: "\f1ba"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tree:before { + content: "\f1bb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-spotify:before { + content: "\f1bc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-deviantart:before { + content: "\f1bd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-soundcloud:before { + content: "\f1be"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-database:before { + content: "\f1c0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-pdf-o:before { + content: "\f1c1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-word-o:before { + content: "\f1c2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-excel-o:before { + content: "\f1c3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-powerpoint-o:before { + content: "\f1c4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-image-o:before, .fa-file-photo-o:before, .fa-file-picture-o:before { + content: "\f1c5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-archive-o:before, .fa-file-zip-o:before { + content: "\f1c6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-audio-o:before, .fa-file-sound-o:before { + content: "\f1c7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: "\f1c8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-file-code-o:before { + content: "\f1c9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-vine:before { + content: "\f1ca"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-codepen:before { + content: "\f1cb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-jsfiddle:before { + content: "\f1cc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-life-bouy:before, .fa-life-buoy:before, .fa-life-ring:before, .fa-life-saver:before, .fa-support:before { + content: "\f1cd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-circle-o-notch:before { + content: "\f1ce"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ra:before, .fa-rebel:before { + content: "\f1d0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-empire:before, .fa-ge:before { + content: "\f1d1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-git-square:before { + content: "\f1d2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-git:before { + content: "\f1d3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-hacker-news:before { + content: "\f1d4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tencent-weibo:before { + content: "\f1d5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-qq:before { + content: "\f1d6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-wechat:before, +.fa-weixin:before { + content: "\f1d7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paper-plane:before, .fa-send:before { + content: "\f1d8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paper-plane-o:before, .fa-send-o:before { + content: "\f1d9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-history:before { + content: "\f1da"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-circle-thin:before, .fa-genderless:before { + content: "\f1db"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-header:before { + content: "\f1dc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paragraph:before { + content: "\f1dd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sliders:before { + content: "\f1de"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-share-alt:before { + content: "\f1e0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-share-alt-square:before { + content: "\f1e1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bomb:before { + content: "\f1e2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-futbol-o:before, .fa-soccer-ball-o:before { + content: "\f1e3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-tty:before { + content: "\f1e4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-binoculars:before { + content: "\f1e5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-plug:before { + content: "\f1e6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-slideshare:before { + content: "\f1e7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-twitch:before { + content: "\f1e8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-yelp:before { + content: "\f1e9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-newspaper-o:before { + content: "\f1ea"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-wifi:before { + content: "\f1eb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-calculator:before { + content: "\f1ec"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paypal:before { + content: "\f1ed"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-google-wallet:before { + content: "\f1ee"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-visa:before { + content: "\f1f0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-mastercard:before { + content: "\f1f1"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-discover:before { + content: "\f1f2"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-amex:before { + content: "\f1f3"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-paypal:before { + content: "\f1f4"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc-stripe:before { + content: "\f1f5"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bell-slash:before { + content: "\f1f6"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bell-slash-o:before { + content: "\f1f7"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-trash:before { + content: "\f1f8"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-copyright:before { + content: "\f1f9"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-at:before { + content: "\f1fa"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-eyedropper:before { + content: "\f1fb"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-paint-brush:before { + content: "\f1fc"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-birthday-cake:before { + content: "\f1fd"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-area-chart:before { + content: "\f1fe"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pie-chart:before { + content: "\f200"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-line-chart:before { + content: "\f201"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lastfm:before { + content: "\f202"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-lastfm-square:before { + content: "\f203"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-toggle-off:before { + content: "\f204"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-toggle-on:before { + content: "\f205"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bicycle:before { + content: "\f206"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bus:before { + content: "\f207"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ioxhost:before { + content: "\f208"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-angellist:before { + content: "\f209"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cc:before { + content: "\f20a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ils:before, .fa-shekel:before, .fa-sheqel:before { + content: "\f20b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-meanpath:before { + content: "\f20c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-buysellads:before { + content: "\f20d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-connectdevelop:before { + content: "\f20e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-dashcube:before { + content: "\f210"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-forumbee:before { + content: "\f211"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-leanpub:before { + content: "\f212"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-sellsy:before { + content: "\f213"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-shirtsinbulk:before { + content: "\f214"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-simplybuilt:before { + content: "\f215"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-skyatlas:before { + content: "\f216"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cart-plus:before { + content: "\f217"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-cart-arrow-down:before { + content: "\f218"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-diamond:before { + content: "\f219"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-ship:before { + content: "\f21a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-user-secret:before { + content: "\f21b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-motorcycle:before { + content: "\f21c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-street-view:before { + content: "\f21d"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-heartbeat:before { + content: "\f21e"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-venus:before { + content: "\f221"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mars:before { + content: "\f222"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mercury:before { + content: "\f223"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-transgender:before { + content: "\f224"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-transgender-alt:before { + content: "\f225"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-venus-double:before { + content: "\f226"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mars-double:before { + content: "\f227"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-venus-mars:before { + content: "\f228"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mars-stroke:before { + content: "\f229"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mars-stroke-v:before { + content: "\f22a"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-mars-stroke-h:before { + content: "\f22b"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-neuter:before { + content: "\f22c"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-facebook-official:before { + content: "\f230"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-pinterest-p:before { + content: "\f231"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-whatsapp:before { + content: "\f232"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-server:before { + content: "\f233"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-user-plus:before { + content: "\f234"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-user-times:before { + content: "\f235"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-bed:before, .fa-hotel:before { + content: "\f236"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-viacoin:before { + content: "\f237"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-train:before { + content: "\f238"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-subway:before { + content: "\f239"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.fa-medium:before { + content: "\f23a"; +} + +/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ +@font-face { + font-family: editormd-logo; + src: url(../fonts/editormd-logo.eot?-5y8q6h); + src: url(.../fonts/editormd-logo.eot?#iefix-5y8q6h) format("embedded-opentype"), url(../fonts/editormd-logo.woff?-5y8q6h) format("woff"), url(../fonts/editormd-logo.ttf?-5y8q6h) format("truetype"), url(../fonts/editormd-logo.svg?-5y8q6h#icomoon) format("svg"); + font-weight: 400; + font-style: normal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo, .editormd-logo-1x, .editormd-logo-2x, .editormd-logo-3x, .editormd-logo-4x, .editormd-logo-5x, .editormd-logo-6x, .editormd-logo-7x, .editormd-logo-8x { + font-family: editormd-logo; + speak: none; + font-style: normal; + font-weight: 400; + font-variant: normal; + text-transform: none; + font-size: inherit; + line-height: 1; + display: inline-block; + text-rendering: auto; + vertical-align: inherit; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body hr:after, .markdown-body hr:before { + content: ""; + display: table; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-1x:before, .editormd-logo-2x:before, .editormd-logo-3x:before, .editormd-logo-4x:before, .editormd-logo-5x:before, .editormd-logo-6x:before, .editormd-logo-7x:before, .editormd-logo-8x:before, .editormd-logo:before { + content: "\e1987"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-1x { + font-size: 1em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-lg { + font-size: 1.2em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-2x { + font-size: 2em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-3x { + font-size: 3em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-4x { + font-size: 4em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-5x { + font-size: 5em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-6x { + font-size: 6em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-7x { + font-size: 7em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-8x { + font-size: 8em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-logo-color { + color: #2196F3; +} + +/*! github-markdown-css | The MIT License (MIT) | Copyright (c) Sindre Sorhus (sindresorhus.com) | https://github.com/sindresorhus/github-markdown-css */ +@font-face { + font-family: octicons-anchor; + src: url(data:font/woff;charset=utf-8;base64,d09GRgABAAAAAAYcAA0AAAAACjQAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABMAAAABwAAAAca8vGTk9TLzIAAAFMAAAARAAAAFZG1VHVY21hcAAAAZAAAAA+AAABQgAP9AdjdnQgAAAB0AAAAAQAAAAEACICiGdhc3AAAAHUAAAACAAAAAj//wADZ2x5ZgAAAdwAAADRAAABEKyikaNoZWFkAAACsAAAAC0AAAA2AtXoA2hoZWEAAALgAAAAHAAAACQHngNFaG10eAAAAvwAAAAQAAAAEAwAACJsb2NhAAADDAAAAAoAAAAKALIAVG1heHAAAAMYAAAAHwAAACABEAB2bmFtZQAAAzgAAALBAAAFu3I9x/Nwb3N0AAAF/AAAAB0AAAAvaoFvbwAAAAEAAAAAzBdyYwAAAADP2IQvAAAAAM/bz7t4nGNgZGFgnMDAysDB1Ml0hoGBoR9CM75mMGLkYGBgYmBlZsAKAtJcUxgcPsR8iGF2+O/AEMPsznAYKMwIkgMA5REMOXicY2BgYGaAYBkGRgYQsAHyGMF8FgYFIM0ChED+h5j//yEk/3KoSgZGNgYYk4GRCUgwMaACRoZhDwCs7QgGAAAAIgKIAAAAAf//AAJ4nHWMMQrCQBBF/0zWrCCIKUQsTDCL2EXMohYGSSmorScInsRGL2DOYJe0Ntp7BK+gJ1BxF1stZvjz/v8DRghQzEc4kIgKwiAppcA9LtzKLSkdNhKFY3HF4lK69ExKslx7Xa+vPRVS43G98vG1DnkDMIBUgFN0MDXflU8tbaZOUkXUH0+U27RoRpOIyCKjbMCVejwypzJJG4jIwb43rfl6wbwanocrJm9XFYfskuVC5K/TPyczNU7b84CXcbxks1Un6H6tLH9vf2LRnn8Ax7A5WQAAAHicY2BkYGAA4teL1+yI57f5ysDNwgAC529f0kOmWRiYVgEpDgYmEA8AUzEKsQAAAHicY2BkYGB2+O/AEMPCAAJAkpEBFbAAADgKAe0EAAAiAAAAAAQAAAAEAAAAAAAAKgAqACoAiAAAeJxjYGRgYGBhsGFgYgABEMkFhAwM/xn0QAIAD6YBhwB4nI1Ty07cMBS9QwKlQapQW3VXySvEqDCZGbGaHULiIQ1FKgjWMxknMfLEke2A+IJu+wntrt/QbVf9gG75jK577Lg8K1qQPCfnnnt8fX1NRC/pmjrk/zprC+8D7tBy9DHgBXoWfQ44Av8t4Bj4Z8CLtBL9CniJluPXASf0Lm4CXqFX8Q84dOLnMB17N4c7tBo1AS/Qi+hTwBH4rwHHwN8DXqQ30XXAS7QaLwSc0Gn8NuAVWou/gFmnjLrEaEh9GmDdDGgL3B4JsrRPDU2hTOiMSuJUIdKQQayiAth69r6akSSFqIJuA19TrzCIaY8sIoxyrNIrL//pw7A2iMygkX5vDj+G+kuoLdX4GlGK/8Lnlz6/h9MpmoO9rafrz7ILXEHHaAx95s9lsI7AHNMBWEZHULnfAXwG9/ZqdzLI08iuwRloXE8kfhXYAvE23+23DU3t626rbs8/8adv+9DWknsHp3E17oCf+Z48rvEQNZ78paYM38qfk3v/u3l3u3GXN2Dmvmvpf1Srwk3pB/VSsp512bA/GG5i2WJ7wu430yQ5K3nFGiOqgtmSB5pJVSizwaacmUZzZhXLlZTq8qGGFY2YcSkqbth6aW1tRmlaCFs2016m5qn36SbJrqosG4uMV4aP2PHBmB3tjtmgN2izkGQyLWprekbIntJFing32a5rKWCN/SdSoga45EJykyQ7asZvHQ8PTm6cslIpwyeyjbVltNikc2HTR7YKh9LBl9DADC0U/jLcBZDKrMhUBfQBvXRzLtFtjU9eNHKin0x5InTqb8lNpfKv1s1xHzTXRqgKzek/mb7nB8RZTCDhGEX3kK/8Q75AmUM/eLkfA+0Hi908Kx4eNsMgudg5GLdRD7a84npi+YxNr5i5KIbW5izXas7cHXIMAau1OueZhfj+cOcP3P8MNIWLyYOBuxL6DRylJ4cAAAB4nGNgYoAALjDJyIAOWMCiTIxMLDmZedkABtIBygAAAA==) format("woff"); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + color: #333; + overflow: hidden; + font-family: "Microsoft YaHei",Helvetica,"Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Monaco,monospace,Tahoma,STXihei,"华文细黑",STHeiti,"Helvetica Neue","Droid Sans","wenquanyi micro hei",FreeSans,Arimo,Arial,SimSun,"宋体",Heiti,"黑体",sans-serif; + font-size: 16px; + line-height: 1.6; + word-wrap: break-word; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body strong { + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1 { + margin: .67em 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body img { + border: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body hr { + box-sizing: content-box; + height: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body input { + color: inherit; + margin: 0; + line-height: normal; + font: 13px/1.4 Helvetica,arial,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body html input[disabled] { + cursor: default; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body input[type=checkbox] { + box-sizing: border-box; + padding: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body * { + box-sizing: border-box; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body a { + background: 0 0; + color: #4183c4; + text-decoration: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body a:active, .markdown-body a:hover { + outline: 0; + text-decoration: underline; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body hr { + margin: 15px 0; + overflow: hidden; + background: 0 0; + border: 0; + border-bottom: 1px solid #ddd; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1, .markdown-body h2 { + padding-bottom: .3em; + border-bottom: 1px solid #eee; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body blockquote { + margin: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body ol ol, .markdown-body ul ol { + list-style-type: lower-roman; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body ol ol ol, .markdown-body ol ul ol, .markdown-body ul ol ol, .markdown-body ul ul ol { + list-style-type: lower-alpha; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body dd { + margin-left: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body code { + font-family: Consolas,"Liberation Mono",Menlo,Courier,monospace; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body pre { + font: 12px Consolas,"Liberation Mono",Menlo,Courier,monospace; + word-wrap: normal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .octicon { + font: normal normal 16px octicons-anchor; + line-height: 1; + display: inline-block; + text-decoration: none; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .octicon-link:before { + content: '\f05c'; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body > :first-child { + margin-top: 0 !important; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body > :last-child { + margin-bottom: 0 !important; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .anchor { + position: absolute; + top: 0; + left: 0; + display: block; + padding-right: 6px; + padding-left: 30px; + margin-left: -30px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .anchor:focus { + outline: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1, .markdown-body h2, .markdown-body h3, .markdown-body h4, .markdown-body h5, .markdown-body h6 { + position: relative; + margin-top: 1em; + margin-bottom: 16px; + font-weight: 700; + line-height: 1.4; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1 .octicon-link, .markdown-body h2 .octicon-link, .markdown-body h3 .octicon-link, .markdown-body h4 .octicon-link, .markdown-body h5 .octicon-link, .markdown-body h6 .octicon-link { + display: none; + color: #000; + vertical-align: middle; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1:hover .anchor, .markdown-body h2:hover .anchor, .markdown-body h3:hover .anchor, .markdown-body h4:hover .anchor, .markdown-body h5:hover .anchor, .markdown-body h6:hover .anchor { + padding-left: 8px; + margin-left: -30px; + text-decoration: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1:hover .anchor .octicon-link, .markdown-body h2:hover .anchor .octicon-link, .markdown-body h3:hover .anchor .octicon-link, .markdown-body h4:hover .anchor .octicon-link, .markdown-body h5:hover .anchor .octicon-link, .markdown-body h6:hover .anchor .octicon-link { + display: inline-block; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1 { + font-size: 2.25em; + line-height: 1.2; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h1 .anchor { + line-height: 1; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h2 { + font-size: 1.75em; + line-height: 1.225; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h2 .anchor { + line-height: 1; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h3 { + font-size: 1.5em; + line-height: 1.43; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h3 .anchor, .markdown-body h4 .anchor { + line-height: 1.2; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h4 { + font-size: 1.25em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h5 .anchor, .markdown-body h6 .anchor { + line-height: 1.1; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h5 { + font-size: 1em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body h6 { + font-size: 1em; + color: #777; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body blockquote, .markdown-body dl, .markdown-body ol, .markdown-body p, .markdown-body pre, .markdown-body table, .markdown-body ul { + margin-top: 0; + margin-bottom: 16px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body ol, .markdown-body ul { + padding-left: 2em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body ol ol, .markdown-body ol ul, .markdown-body ul ol, .markdown-body ul ul { + margin-top: 0; + margin-bottom: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body li > p { + margin-top: 16px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body dl { + padding: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body blockquote { + padding: 0 15px; + color: #777; + border-left: 4px solid #ddd; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body blockquote > :first-child { + margin-top: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body blockquote > :last-child { + margin-bottom: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body table { + border-collapse: collapse; + border-spacing: 0; + display: block; + width: 100%; + overflow: auto; + word-break: normal; + word-break: keep-all; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body table th { + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body table td, .markdown-body table th { + padding: 6px 13px; + border: 1px solid #ddd; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body table tr { + background-color: #fff; + border-top: 1px solid #ccc; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body table tr:nth-child(2n) { + background-color: #f8f8f8; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body img { + max-width: 100%; + box-sizing: border-box; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body code { + padding: .2em 0; + margin: 0; + font-size: 85%; + background-color: rgba(0, 0, 0, 0.04); + border-radius: 3px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body code:after, .markdown-body code:before { + letter-spacing: -.2em; + content: "\00a0"; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body pre > code { + padding: 0; + margin: 0; + font-size: 100%; + word-break: normal; + white-space: pre; + background: 0 0; + border: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .highlight { + margin-bottom: 16px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .highlight pre, .markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + background-color: #f7f7f7; + border-radius: 3px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body pre code { + display: inline; + max-width: initial; + padding: 0; + margin: 0; + overflow: initial; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body pre code:after, .markdown-body pre code:before { + content: normal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-c { + color: #969896; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-c1, .markdown-body .pl-mdh, .markdown-body .pl-mm, .markdown-body .pl-mp, .markdown-body .pl-mr, .markdown-body .pl-s1 .pl-v, .markdown-body .pl-s3, .markdown-body .pl-sc, .markdown-body .pl-sv { + color: #0086b3; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-e, .markdown-body .pl-en { + color: #795da3; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-s1 .pl-s2, .markdown-body .pl-smi, .markdown-body .pl-smp, .markdown-body .pl-stj, .markdown-body .pl-vo, .markdown-body .pl-vpf { + color: #333; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-ent { + color: #63a35c; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-k, .markdown-body .pl-s, .markdown-body .pl-st { + color: #a71d5d; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-pds, .markdown-body .pl-s1, .markdown-body .pl-s1 .pl-pse .pl-s2, .markdown-body .pl-sr, .markdown-body .pl-sr .pl-cce, .markdown-body .pl-sr .pl-sra, .markdown-body .pl-sr .pl-sre, .markdown-body .pl-src { + color: #df5000; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mo, .markdown-body .pl-v { + color: #1d3e81; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-id { + color: #b52a1d; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-ii { + background-color: #b52a1d; + color: #f8f8f8; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-sr .pl-cce { + color: #63a35c; + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-ml { + color: #693a17; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mh, .markdown-body .pl-mh .pl-en, .markdown-body .pl-ms { + color: #1d3e81; + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mq { + color: teal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mi { + color: #333; + font-style: italic; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mb { + color: #333; + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-md, .markdown-body .pl-mdhf { + background-color: #ffecec; + color: #bd2c00; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mdht, .markdown-body .pl-mi1 { + background-color: #eaffea; + color: #55a532; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .pl-mdr { + color: #795da3; + font-weight: 700; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font: 11px Consolas,"Liberation Mono",Menlo,Courier,monospace; + line-height: 10px; + color: #555; + vertical-align: middle; + background-color: #fcfcfc; + border: 1px solid #ccc; + border-bottom-color: #bbb; + border-radius: 3px; + box-shadow: inset 0 -1px 0 #bbb; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .task-list-item + .task-list-item { + margin-top: 3px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .task-list-item input { + float: left; + margin: .3em 0 .25em -1.6em; + vertical-align: middle; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body :checked + .radio-label { + z-index: 1; + position: relative; + border-color: #4183c4; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview, .editormd-preview-container { + text-align: left; + font-size: 14px; + line-height: 1.6; + padding: 20px; + overflow: auto; + width: 100%; + background-color: #fff; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview blockquote, .editormd-preview-container blockquote { + color: #666; + border-left: 4px solid #ddd; + padding-left: 20px; + margin-left: 0; + font-size: 14px; + font-style: italic; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview p code, .editormd-preview-container p code { + margin-left: 5px; + margin-right: 4px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview abbr, .editormd-preview-container abbr { + background: #ffd; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview hr, .editormd-preview-container hr { + height: 1px; + border: none; + border-top: 1px solid #ddd; + background: 0 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview code, .editormd-preview-container code { + border: 1px solid #ddd; + background: #f6f6f6; + padding: 3px; + border-radius: 3px; + font-size: 14px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview pre, .editormd-preview-container pre { + border: 1px solid #ddd; + background: #f6f6f6; + padding: 10px; + border-radius: 3px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview pre code, .editormd-preview-container pre code { + padding: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview code, .editormd-html-preview kbd, .editormd-html-preview pre, .editormd-preview-container code, .editormd-preview-container kbd, .editormd-preview-container pre { + font-family: "YaHei Consolas Hybrid",Consolas,"Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,monospace,monospace; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview table thead tr, .editormd-preview-container table thead tr { + background-color: #F8F8F8; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview p.editormd-tex, .editormd-preview-container p.editormd-tex { + text-align: center; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview span.editormd-tex, .editormd-preview-container span.editormd-tex { + margin: 0 5px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .emoji, .editormd-preview-container .emoji { + width: 24px; + height: 24px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .katex, .editormd-preview-container .katex { + font-size: 1.4em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .flowchart, .editormd-html-preview .sequence-diagram, .editormd-preview-container .flowchart, .editormd-preview-container .sequence-diagram { + margin: 0 auto; + text-align: center; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .flowchart svg, .editormd-html-preview .sequence-diagram svg, .editormd-preview-container .flowchart svg, .editormd-preview-container .sequence-diagram svg { + margin: 0 auto; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .flowchart text, .editormd-html-preview .sequence-diagram text, .editormd-preview-container .flowchart text, .editormd-preview-container .sequence-diagram text { + font-size: 15px !important; + font-family: "YaHei Consolas Hybrid", Consolas, "Microsoft YaHei", "Malgun Gothic", "Segoe UI", Helvetica, Arial !important; +} + +/*! Pretty printing styles. Used with prettify.js. */ +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.pln { + color: #000; +} + +@media screen { + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .str { + color: #080; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .kwd { + color: #008; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .com { + color: #800; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .typ { + color: #606; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .lit { + color: #066; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .clo, .opn, .pun { + color: #660; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .tag { + color: #008; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .atn { + color: #606; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .atv { + color: #080; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .dec, .var { + color: #606; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .fun { + color: red; + } +} + +@media print, projection { + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .kwd, .tag, .typ { + font-weight: 700; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .str { + color: #060; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .kwd { + color: #006; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .com { + color: #600; + font-style: italic; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .typ { + color: #404; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .lit { + color: #044; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .clo, .opn, .pun { + color: #440; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .tag { + color: #006; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .atn { + color: #404; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .atv { + color: #060; + } +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +pre.prettyprint { + padding: 2px; + border: 1px solid #888; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +li.L1, li.L3, li.L5, li.L7, li.L9 { + background: #eee; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview pre.prettyprint, .editormd-preview-container pre.prettyprint { + padding: 10px; + border: 1px solid #ddd; + white-space: pre-wrap; + word-wrap: break-word; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview ol.linenums, .editormd-preview-container ol.linenums { + color: #999; + padding-left: 2.5em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview ol.linenums li, .editormd-preview-container ol.linenums li { + list-style-type: decimal; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview ol.linenums li code, .editormd-preview-container ol.linenums li code { + border: none; + background: 0 0; + padding: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu, .editormd-preview-container .editormd-toc-menu { + margin: 8px 0 12px; + display: inline-block; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc, .editormd-preview-container .editormd-toc-menu > .markdown-toc { + position: relative; + border-radius: 4px; + border: 1px solid #ddd; + display: inline-block; + font-size: 1em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc > ul, .editormd-preview-container .editormd-toc-menu > .markdown-toc > ul { + width: 160%; + min-width: 180px; + position: absolute; + left: -1px; + top: -2px; + z-index: 100; + padding: 0 10px 10px; + display: none; + background: #fff; + border: 1px solid #ddd; + border-radius: 4px; + -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); + -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); + box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li ul, .editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li ul { + width: 100%; + min-width: 180px; + border: 1px solid #ddd; + display: none; + background: #fff; + border-radius: 4px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu .toc-menu-btn:hover, .editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a:hover, .editormd-preview-container .editormd-toc-menu .toc-menu-btn:hover, .editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a:hover { + background-color: #f6f6f6; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc > ul > li a, .editormd-preview-container .editormd-toc-menu > .markdown-toc > ul > li a { + color: #666; + padding: 6px 10px; + display: block; + -webkit-transition: background-color 500ms ease-out; + transition: background-color 500ms ease-out; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc li, .editormd-preview-container .editormd-toc-menu > .markdown-toc li { + position: relative; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul { + position: absolute; + top: 32px; + left: 10%; + display: none; + -ms-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); + -o-box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); + box-shadow: 0 3px 5px rgba(0, 0, 0, 0.2); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before { + pointer-events: pointer-events; + position: absolute; + left: 15px; + top: -6px; + display: block; + content: ""; + width: 0; + height: 0; + border: 6px solid transparent; + border-width: 0 6px 6px; + z-index: 10; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:before, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:before { + border-bottom-color: #ccc; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu > .markdown-toc li > ul:after, .editormd-preview-container .editormd-toc-menu > .markdown-toc li > ul:after { + border-bottom-color: #fff; + top: -5px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu ul, .editormd-preview-container .editormd-toc-menu ul { + list-style: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu a, .editormd-preview-container .editormd-toc-menu a { + text-decoration: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu h1, .editormd-preview-container .editormd-toc-menu h1 { + font-size: 16px; + padding: 5px 0 10px 10px; + line-height: 1; + border-bottom: 1px solid #eee; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu h1 .fa, .editormd-preview-container .editormd-toc-menu h1 .fa { + padding-left: 10px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu .toc-menu-btn, .editormd-preview-container .editormd-toc-menu .toc-menu-btn { + color: #666; + min-width: 180px; + padding: 5px 10px; + border-radius: 4px; + display: inline-block; + -webkit-transition: background-color 500ms ease-out; + transition: background-color 500ms ease-out; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview textarea, .editormd-onlyread .editormd-toolbar { + display: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview .editormd-toc-menu .toc-menu-btn .fa, .editormd-preview-container .editormd-toc-menu .toc-menu-btn .fa { + float: right; + padding: 3px 0 0 10px; + font-size: 1.3em; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .editormd-toc-menu ul { + padding-left: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.markdown-body .highlight pre, .markdown-body pre { + line-height: 1.6; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +hr.editormd-page-break { + border: 1px dotted #ccc; + font-size: 0; + height: 2px; +} + +@media only print { + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + hr.editormd-page-break { + background: 0 0; + border: none; + height: 0; + } +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview hr.editormd-page-break { + background: 0 0; + border: none; + height: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-close-btn { + color: #fff; + padding: 4px 6px; + font-size: 18px; + border-radius: 500px; + display: none; + background-color: #ccc; + position: absolute; + top: 25px; + right: 35px; + z-index: 19; + -webkit-transition: background-color 300ms ease-out; + transition: background-color 300ms ease-out; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-close-btn:hover { + background-color: #999; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-active { + width: 100%; + padding: 40px; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark { + color: #777; + background: #2C2827; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container { + color: #888; + background-color: #2C2827; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container pre.prettyprint { + border: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container blockquote { + color: #555; + padding: .5em; + background: #222; + border-color: #333; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container abbr { + color: #fff; + padding: 1px 3px; + border-radius: 3px; + background: #f90; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container code { + color: #fff; + border: none; + padding: 1px 3px; + border-radius: 3px; + background: #5A9600; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container table { + border: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container .fa-emoji { + color: #B4BF42; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container .katex { + color: #FEC93F; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-toc-menu > .markdown-toc { + background: #fff; + border: none; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-toc-menu > .markdown-toc h1 { + border-color: #ddd; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .markdown-body h1, .editormd-preview-theme-dark .markdown-body h2, .editormd-preview-theme-dark .markdown-body hr { + border-color: #222; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark pre { + color: #999; + background-color: #111; + background-color: rgba(0, 0, 0, 0.4); +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark pre .pln { + color: #999; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark li.L1, .editormd-preview-theme-dark li.L3, .editormd-preview-theme-dark li.L5, .editormd-preview-theme-dark li.L7, .editormd-preview-theme-dark li.L9 { + background: 0 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark [class*=editormd-logo] { + color: #2196F3; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .sequence-diagram text { + fill: #fff; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .sequence-diagram path, .editormd-preview-theme-dark .sequence-diagram rect { + color: #fff; + fill: #64D1CB; + stroke: #64D1CB; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart path, .editormd-preview-theme-dark .flowchart rect { + stroke: #A6C6FF; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart rect { + fill: #A6C6FF; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart text { + fill: #5879B4; +} + +@media screen { + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .str { + color: #080; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .kwd { + color: #f90; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .com { + color: #444; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .typ { + color: #606; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .lit { + color: #066; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .clo, .editormd-preview-theme-dark .opn, .editormd-preview-theme-dark .pun { + color: #660; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .tag { + color: #f90; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .atn { + color: #6C95F5; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .atv { + color: #080; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .dec, .editormd-preview-theme-dark .var { + color: #008BA7; + } + /* line 5, vendor/assets/editormd/css/editormd.min.css */ + .editormd-preview-theme-dark .fun { + color: red; + } +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-onlyread .CodeMirror { + margin-top: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-onlyread .editormd-preview { + top: 0; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-fullscreen { + position: fixed; + top: 0; + left: 0; + border: none; + margin: 0 auto; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark { + border-color: #1a1a17; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-toolbar { + background: #1A1A17; + border-color: #1a1a17; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-menu > li > a { + color: #777; + border-color: #1a1a17; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-menu > li > a.active, .editormd-theme-dark .editormd-menu > li > a:hover { + border-color: #333; + background: #333; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-menu > li.divider { + border-right: 1px solid #111; +} + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .CodeMirror { + border-right: 1px solid rgba(0, 0, 0, 0.1); +} + +/* line 1, vendor/assets/dragula/dragula.css */ +.gu-mirror { + position: fixed !important; + margin: 0 !important; + z-index: 9999 !important; + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); +} + +/* line 9, vendor/assets/dragula/dragula.css */ +.gu-hide { + display: none !important; +} + +/* line 12, vendor/assets/dragula/dragula.css */ +.gu-unselectable { + -webkit-user-select: none !important; + -moz-user-select: none !important; + -ms-user-select: none !important; + user-select: none !important; +} + +/* line 18, vendor/assets/dragula/dragula.css */ +.gu-transit { + opacity: 0.2; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=20)"; + filter: alpha(opacity=20); +} + /* line 1, app/assets/stylesheets/common.scss */ body { font-size: 14px; @@ -18594,6 +23570,157 @@ input.form-control { font-size: 18px !important; } +/* line 37, app/assets/stylesheets/common.scss */ +.padding10-5 { + padding: 10px 5px; +} + +/* line 38, app/assets/stylesheets/common.scss */ +.width100 { + width: 100%; +} + +/* line 39, app/assets/stylesheets/common.scss */ +.mb10 { + margin-bottom: 10px; +} + +/* line 40, app/assets/stylesheets/common.scss */ +.mt10 { + margin-top: 10px; +} + +/* line 41, app/assets/stylesheets/common.scss */ +.mr10 { + margin-right: 10px; +} + +/* line 42, app/assets/stylesheets/common.scss */ +.textarea-width-100 { + width: 100%; + resize: none; + border: 1px solid #ccc; +} + +/* line 43, app/assets/stylesheets/common.scss */ +.padding10 { + padding: 10px; +} + +/* line 44, app/assets/stylesheets/common.scss */ +.padding5-10 { + padding: 5px 10px; +} + +/* line 45, app/assets/stylesheets/common.scss */ +.position-r { + position: relative; +} + +/* line 46, app/assets/stylesheets/common.scss */ +.color-grey-c { + color: #ccc; +} + +/* line 47, app/assets/stylesheets/common.scss */ +.inline-block { + display: inline-block; +} + +/* line 48, app/assets/stylesheets/common.scss */ +.hide { + display: none; +} + +/* line 49, app/assets/stylesheets/common.scss */ +.show { + display: block; +} + +/* line 2, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .list-item-title { + padding-bottom: 5px; + padding-left: 33px; + color: #555; +} + +/* line 7, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .list-item-title-1 { + width: 100px; + display: inline-block; +} + +/* line 11, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .list-item-title-2 { + width: 200px; + display: inline-block; +} + +/* line 15, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .collegeManage { + float: left; + padding: 0px 8px; + border-radius: 6px; + background-color: #f5f5f5; + margin: 3px 0px 3px 10px; + height: 34px; + line-height: 34px; +} + +/* line 23, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .collegeManage a { + color: #05101a; +} + +/* line 26, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .collegeManage a:hover { + color: #007bff; +} + +/* line 30, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page i:hover { + color: #333; +} + +/* line 33, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .add-manager-i { + float: left; +} + +/* line 35, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .add-manager-i i { + padding: 10px 5px; +} + +/* line 41, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .auth-schools-new-add .flex-column input, .admins-auth-schools-index-page .auth-schools-user-add .flex-column input { + height: 38px; +} + +/* line 45, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .auth-schools-new-add .search-school, .admins-auth-schools-index-page .auth-schools-user-add .search-school { + margin-left: 15px; +} + +/* line 50, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .school-search-list { + background: #F4FAFF; + height: 280px; + overflow-y: scroll; + padding: 10px 0; +} + +/* line 56, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .school-list-item { + padding: 2px 10px; +} + +/* line 58, app/assets/stylesheets/admins/auth_schools.scss */ +.admins-auth-schools-index-page .school-list-item input { + font-size: 20px; + margin-right: 5px; +} + /* line 1, app/assets/stylesheets/admins/common.scss */ .admin-body-container { padding: 20px; @@ -18735,6 +23862,41 @@ input.form-control { border: 1px solid #ced4da; } +/* line 4, app/assets/stylesheets/admins/cooperatives.scss */ +.admins-cooperatives-index-page .coo-img-card .coo-img-item > .drag { + cursor: move; + background: #fff; + box-shadow: 1px 2px 5px 3px #f0f0f0; +} + +/* line 10, app/assets/stylesheets/admins/cooperatives.scss */ +.admins-cooperatives-index-page .coo-img-card .coo-img-item-img { + cursor: pointer; + width: 100%; + height: 40px; + margin-bottom: 10px; +} + +/* line 16, app/assets/stylesheets/admins/cooperatives.scss */ +.admins-cooperatives-index-page .coo-img-card .coo-img-item-img > img { + width: 100%; + height: 40px; +} + +/* line 22, app/assets/stylesheets/admins/cooperatives.scss */ +.admins-cooperatives-index-page .coo-img-card .coo-img-item .delete-btn { + position: absolute; + top: 3px; + right: 20px; + color: red; + cursor: pointer; +} + +/* line 30, app/assets/stylesheets/admins/cooperatives.scss */ +.admins-cooperatives-index-page .coo-img-card .coo-img-item .save-url-btn { + cursor: pointer; +} + /* line 2, app/assets/stylesheets/admins/daily_school_statistics.scss */ .admins-daily-school-statistics-index-page .daily-school-statistic-list-container { text-align: center; @@ -18770,6 +23932,29 @@ input.form-control { border-radius: 4px; } +/* line 2, app/assets/stylesheets/admins/ec_tempaltes.scss */ +.admins-ec-templates-index-page .template-file-upload { + padding: 10px; + background: #fafafa; + border: 1px dashed #ccc; + text-align: center; + color: #999; + position: relative; + width: 100%; +} + +/* line 12, app/assets/stylesheets/admins/ec_tempaltes.scss */ +.admins-ec-templates-index-page input[name='file'] { + opacity: 0; + position: absolute; + display: inline-block; + left: 0; + height: 43px; + top: 0; + width: 100%; + cursor: pointer; +} + /* line 4, app/assets/stylesheets/admins/identity_authentications.scss */ .admins-identity-authentications-index-page .identity-authentication-list-container span.apply-status-1 { color: #28a745; @@ -18800,6 +23985,53 @@ input.form-control { color: #6c757d; } +/* line 2, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .fr { + float: right; +} + +/* line 5, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default { + margin-bottom: 10px; + background-color: whitesmoke; +} + +/* line 9, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-heading i { + margin-right: 15px; + font-size: 16px; + color: #cccccc; +} + +/* line 14, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-heading a { + padding: 8px 10px; + display: inline-block; + width: 100%; + color: #666666; +} + +/* line 21, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-collapse { + padding-top: 10px; + background: #fff; +} + +/* line 24, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-collapse table { + text-align: center; +} + +/* line 26, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-collapse table th, .admins-major-informations-index-page .panel-default .panel-collapse table td { + padding: 8px; +} + +/* line 29, app/assets/stylesheets/admins/major_informations.scss */ +.admins-major-informations-index-page .panel-default .panel-collapse table td { + color: #888; +} + /* line 4, app/assets/stylesheets/admins/professional_authentications.scss */ .admins-professional-authentications-index-page .professional-authentication-list-container span.apply-status-1 { color: #28a745; @@ -19265,7 +24497,7 @@ input.form-control { color: #6c757d; } -/* line 14, app/assets/stylesheets/admin.scss */ +/* line 17, app/assets/stylesheets/admin.scss */ body { width: 100vw; height: 100vh; @@ -19280,34 +24512,29 @@ body { overflow: hidden; } -/* line 28, app/assets/stylesheets/admin.scss */ +/* line 31, app/assets/stylesheets/admin.scss */ .simple_form .form-group .collection_radio_buttons { margin-bottom: 0px; } -/* line 32, app/assets/stylesheets/admin.scss */ +/* line 35, app/assets/stylesheets/admin.scss */ .simple_form .form-group .form-check-inline { height: calc(1.5em + 0.75rem + 2px); } -/* line 38, app/assets/stylesheets/admin.scss */ +/* line 41, app/assets/stylesheets/admin.scss */ input.form-control { font-size: 14px; } -/* line 42, app/assets/stylesheets/admin.scss */ +/* line 45, app/assets/stylesheets/admin.scss */ .btn-default { color: #666; background: #e1e1e1 !important; } -/* line 46, app/assets/stylesheets/admin.scss */ +/* line 49, app/assets/stylesheets/admin.scss */ .export-absolute { right: 20px; position: absolute; } - -/* line 50, app/assets/stylesheets/admin.scss */ -.position-r { - position: relative; -} diff --git a/public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css.gz b/public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css.gz new file mode 100644 index 000000000..03040e90c Binary files /dev/null and b/public/assets/admin-a1b3356efe50ff4717cf22475639b5333c5354ba03fd107c9b7a8d4ae76f47aa.css.gz differ diff --git a/public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css.gz b/public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css.gz deleted file mode 100644 index b7881fabb..000000000 Binary files a/public/assets/admin-b74faf008a2cc4c3c2501b52328f6bf886844c2df02702542eebc1d20bcbf1bc.css.gz and /dev/null differ diff --git a/public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js b/public/assets/admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js similarity index 94% rename from public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js rename to public/assets/admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js index 592d75565..ec26c064f 100644 --- a/public/assets/admin-4a8884f205ac21dc21614cb4c0a7807e2412fe016788b075509fe147dd2ba626.js +++ b/public/assets/admin-cd9ca8bacc973ce2dbace30c97f6c40bc08e2c2ee44972f668e738e1902c0121.js @@ -27816,6 +27816,52 @@ $.fn.bootstrapViewer.defaults = { }); } })); +function createMDEditor(element, opts){ + var defaults = { + height: 600, + path: '/editormd/lib/', + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + toolbarIcons: function () { + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + return ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "image", "table", '|', "watch", "clear"] + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + dialogMaskOpacity: 0.6, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: '/api/attachments.json' + } + var options = $.extend({}, defaults, opts); + + return editormd(element, options); +} + +function ajaxErrorNotifyHandler(res) { + var message = ''; + if(res.status !== 500){ + message = res.responseJSON.message; + } else { + message = '系统错误'; + } + return $.notify({message: message}, {type: 'danger'}); +} + +function resetFileInputFunc(file){ + file.after(file.clone().val("")); + file.remove(); +} +; (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : @@ -128036,406 +128082,6223 @@ CodeMirror.defineMIME('text/x-sh', 'shell'); CodeMirror.defineMIME('application/x-sh', 'shell'); }); -!function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今天",monthsTitle:"选择月份",clear:"清除",format:"yyyy-mm-dd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery); -(function( factory ) { - if ( typeof define === "function" && define.amd ) { - define( ["jquery", "../jquery.validate"], factory ); - } else { - factory( jQuery ); - } -}(function( $ ) { - - /* - * Translated default messages for the jQuery validation plugin. - * Locale: ZH (Chinese, 中文 (Zhōngwén), 汉语, 漢語) - */ - $.extend($.validator.messages, { - required: "这是必填字段", - remote: "请修正此字段", - email: "请输入有效的电子邮件地址", - url: "请输入有效的网址", - date: "请输入有效的日期", - dateISO: "请输入有效的日期 (YYYY-MM-DD)", - number: "请输入有效的数字", - digits: "只能输入数字", - creditcard: "请输入有效的信用卡号码", - equalTo: "你的输入不相同", - extension: "请输入有效的后缀", - maxlength: $.validator.format("最多可以输入 {0} 个字符"), - minlength: $.validator.format("最少要输入 {0} 个字符"), - rangelength: $.validator.format("请输入长度在 {0} 到 {1} 之间的字符串"), - range: $.validator.format("请输入范围在 {0} 到 {1} 之间的数值"), - max: $.validator.format("请输入不大于 {0} 的数值"), - min: $.validator.format("请输入不小于 {0} 的数值") - }); - -})); -/*! Select2 4.0.8 | https://github.com/select2/select2/blob/master/LICENSE.md */ - - -!function(){if(jQuery&&jQuery.fn&&jQuery.fn.select2&&jQuery.fn.select2.amd)var n=jQuery.fn.select2.amd;n.define("select2/i18n/zh-CN",[],function(){return{errorLoading:function(){return"无法载入结果。"},inputTooLong:function(n){return"请删除"+(n.input.length-n.maximum)+"个字符"},inputTooShort:function(n){return"请再输入至少"+(n.minimum-n.input.length)+"个字符"},loadingMore:function(){return"载入更多结果…"},maximumSelected:function(n){return"最多只能选择"+n.maximum+"个项目"},noResults:function(){return"未找到结果"},searching:function(){return"搜索中…"},removeAllItems:function(){return"删除所有项目"}}}),n.define,n.require}(); -$(document).on('turbolinks:load', function() { - var $refuseModal = $('.admin-common-refuse-modal'); - if ($refuseModal.length > 0) { - var $form = $refuseModal.find('form.admin-common-refuse-form'); - var $applyIdInput = $refuseModal.find('.modal-body input[name="apply_id"]'); - var $applyTitle = $refuseModal.find('.modal-title'); - - $form.validate({ - errorElement: 'span', - errorClass: 'danger text-danger', - rules: { - reason: { - required: true, - maxlength: 200 - }, - } - }); - - // modal ready fire - $refuseModal.on('show.bs.modal', function (event) { - var $link = $(event.relatedTarget); - - var applyId = $link.data('id'); - var url = $link.data('url'); - var title = $link.data('title'); - var type = $link.data('type'); - var form_method = "POST"; - if(typeof title !== 'undefined'){ - $applyTitle.html(title) - } - if(typeof type !== 'undefined'){ - form_method = type; - } - - $applyIdInput.val(applyId); - $form.data('url', url); - $form.data('type', form_method); - }); - // modal visited fire - $refuseModal.on('shown.bs.modal', function(){ - $refuseModal.find('.modal-body textarea[name="reason"]').focus(); - }); - $refuseModal.on('hide.bs.modal', function () { - $applyIdInput.val(''); - $refuseModal.find('.modal-body textarea[name="reason"]').val(''); - $form.data('url', ''); - }) - - $refuseModal.on('click', '.submit-btn', function(){ - $form.find('.error').html(''); - - if ($form.valid()) { - var url = $form.data('url'); - var form_method = $form.data('type'); +/* + * Editor.md + * + * @file editormd.js + * @version v1.5.0 + * @description Open source online markdown editor. + * @license MIT License + * @author Pandao + * {@link https://github.com/pandao/editor.md} + * @updateTime 2015-06-09 + */ - $.ajax({ - method: form_method, - dataType: 'script', - url: url, - data: $form.serialize(), - }).done(function(){ - $refuseModal.modal('hide'); - }); - } - }); - } -}); -$(document).on('turbolinks:load', function(){ - if ($('body.admins-daily-school-statistics-index-page').length > 0) { - $('.export-action').on('click', function(){ - var form = $(".daily-school-statistic-list-form .search-form") - var exportLink = $(this); - var keyword = form.find("input[name='keyword']").val(); - var url = exportLink.data("url").split('?')[0] + "?keyword=" + keyword; - window.open(url); - }); - } -}) -; -$(document).on('turbolinks:load', function() { - if ($('body.admins-dashboards-index-page').length > 0) { - // 月新增用户 - var monthChart = echarts.init(document.getElementById('month-active-user')); - monthChart.setOption({ - tooltip: { - show: "true", - trigger: 'item', - formatter: '{c0}', - backgroundColor: 'rgba(0,0,0,0.7)', // 背景 - padding: [8, 10], //内边距 - extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影 - axisPointer: { // 坐标轴指示器,坐标轴触发有效 - type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' - } - }, - series : [ +;(function(factory) { + "use strict"; + + // CommonJS/Node.js + if (typeof require === "function" && typeof exports === "object" && typeof module === "object") + { + module.exports = factory; + } + else if (typeof define === "function") // AMD/CMD/Sea.js + { + if (define.amd) // for Require.js { - name: '访问来源', - type: 'pie', - radius: '55%', - data: [] + /* Require.js define replace */ + } + else + { + define(["jquery"], factory); // for Sea.js } - ] - }); - monthChart.showLoading(); - $.get('/admins/dashboards/month_active_user.json').done(function(data){ - monthChart.setOption({ - series: [ - { data: data.data } - ] - }); - - monthChart.hideLoading(); - }); - - - // 近七天评测次数 - // var evaluateChart = echarts.init(document.getElementById('evaluate-pie')); - // evaluateChart.setOption({ - // tooltip: { - // show: "true", - // trigger: 'item', - // formatter: '{c0}', - // backgroundColor: 'rgba(0,0,0,0.7)', // 背景 - // padding: [8, 10], //内边距 - // extraCssText: 'box-shadow: 0 0 3px rgba(255, 255, 255, 0.4);', //添加阴影 - // axisPointer: { // 坐标轴指示器,坐标轴触发有效 - // type: 'shadow' // 默认为直线,可选为:'line' | 'shadow' - // } - // }, - // xAxis: { type: 'category', boundaryGap: false, data: [] }, - // yAxis: { type: 'value' }, - // series: [{ data: [], type: 'line', areaStyle: {} }] - // }); - // evaluateChart.showLoading(); - // $.get('/admins/dashboards/evaluate.json').done(function(data){ - // evaluateChart.setOption({ - // xAxis: { data: data.names }, - // series: [{ data: data.data }] - // }); - // - // evaluateChart.hideLoading(); - // }); - } -}); -$(document).on('turbolinks:load', function() { - var $editModal = $('.department-apply-edit-modal'); - if($editModal.length > 0){ - var $form = $editModal.find('form.department-apply-form'); - var $applyIdInput = $form.find('input[name="id"]'); - $editModal.on('show.bs.modal', function (event) { - var $link = $(event.relatedTarget); - var applyId = $link.data('id'); - $applyIdInput.val(applyId); - }); - $editModal.on('click', '.submit-btn', function(){ - $.ajax({ - method: "PUT", - dataType: 'script', - url: "/admins/department_applies/"+ $applyIdInput.val(), - data: $form.serialize(), - }).done(function(){ - $editModal.modal('hide'); - }); - }); - } -}); -$(document).on('turbolinks:load', function() { - if ($('body.admins-departments-index-page').length > 0) { - var $searchContainer = $('.department-list-form'); - var $searchForm = $searchContainer.find('form.search-form'); - var $list = $('.department-list-container'); - - $searchContainer.on('change', '.form-check-input', function(){ - $searchForm.find('input[type="submit"]').trigger('click'); - }); + } + else + { + window.editormd = factory(); + } + +}(function() { - // ============== 新建部门 =============== - var $modal = $('.modal.admin-create-department-modal'); - var $form = $modal.find('form.admin-create-department-form'); - var $departmentNameInput = $form.find('input[name="department_name"]'); - var $schoolSelect = $modal.find('.school-select'); + /* Require.js assignment replace */ + + "use strict"; + + var $ = (typeof (jQuery) !== "undefined") ? jQuery : Zepto; - $form.validate({ - errorElement: 'span', - errorClass: 'danger text-danger', - rules: { - school_id: { - required: true + if (typeof ($) === "undefined") { + return ; + } + + /** + * editormd + * + * @param {String} id 编辑器的ID + * @param {Object} options 配置选项 Key/Value + * @returns {Object} editormd 返回editormd对象 + */ + + var editormd = function (id, options) { + return new editormd.fn.init(id, options); + }; + + editormd.title = editormd.$name = "Editor.md"; + editormd.version = "1.5.0"; + editormd.homePage = "https://pandao.github.io/editor.md/"; + editormd.classPrefix = "editormd-"; + + editormd.toolbarModes = { + full : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime", "emoji", "html-entities", "pagebreak", "|", + "goto-line", "watch", "preview", "fullscreen", "clear", "search", "|", + "help", "info" + ], + simple : [ + "undo", "redo", "|", + "bold", "del", "italic", "quote", "uppercase", "lowercase", "|", + "h1", "h2", "h3", "h4", "h5", "h6", "|", + "list-ul", "list-ol", "hr", "|", + "watch", "preview", "fullscreen", "|", + "help", "info" + ], + mini : [ + "undo", "redo", "|", + "watch", "preview", "|", + "help", "info" + ] + }; + + editormd.defaults = { + mode : "gfm", //gfm or markdown + name : "", // Form element name + value : "", // value for CodeMirror, if mode not gfm/markdown + theme : "", // Editor.md self themes, before v1.5.0 is CodeMirror theme, default empty + editorTheme : "default", // Editor area, this is CodeMirror theme at v1.5.0 + previewTheme : "", // Preview area theme, default empty + markdown : "", // Markdown source code + appendMarkdown : "", // if in init textarea value not empty, append markdown to textarea + width : "100%", + height : "100%", + path : "./lib/", // Dependents module file directory + pluginPath : "", // If this empty, default use settings.path + "../plugins/" + delay : 300, // Delay parse markdown to html, Uint : ms + autoLoadModules : true, // Automatic load dependent module files + watch : true, + placeholder : "Enjoy Markdown! coding now...", + gotoLine : true, + codeFold : false, + autoHeight : false, + autoFocus : true, + autoCloseTags : true, + searchReplace : true, + syncScrolling : true, // true | false | "single", default true + readOnly : false, + tabSize : 4, + indentUnit : 4, + lineNumbers : true, + lineWrapping : true, + autoCloseBrackets : true, + showTrailingSpace : true, + matchBrackets : true, + indentWithTabs : true, + styleSelectedText : true, + matchWordHighlight : true, // options: true, false, "onselected" + styleActiveLine : true, // Highlight the current line + dialogLockScreen : true, + dialogShowMask : true, + dialogDraggable : true, + dialogMaskBgColor : "#fff", + dialogMaskOpacity : 0.1, + fontSize : "13px", + saveHTMLToTextarea : false, + disabledKeyMaps : [], + + onload : function() {}, + onresize : function() {}, + onchange : function() {}, + onwatch : null, + onunwatch : null, + onpreviewing : function() {}, + onpreviewed : function() {}, + onfullscreen : function() {}, + onfullscreenExit : function() {}, + onscroll : function() {}, + onpreviewscroll : function() {}, + + imageUpload : false, + imageFormats : ["jpg", "jpeg", "gif", "png", "bmp", "webp"], + imageUploadURL : "", + crossDomainUpload : false, + uploadCallbackURL : "", + + toc : true, // Table of contents + tocm : false, // Using [TOCM], auto create ToC dropdown menu + tocTitle : "", // for ToC dropdown menu btn + tocDropdown : false, + tocContainer : "", + tocStartLevel : 1, // Said from H1 to create ToC + htmlDecode : false, // Open the HTML tag identification + pageBreak : true, // Enable parse page break [========] + atLink : true, // for @link + emailLink : true, // for email address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Github emoji, Twitter Emoji (Twemoji); + // Support FontAwesome icon emoji :fa-xxx: > Using fontAwesome icon web fonts; + // Support Editor.md logo icon emoji :editormd-logo: :editormd-logo-1x: > 1~8x; + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + previewCodeHighlight : true, + + toolbar : true, // show/hide toolbar + toolbarAutoFixed : true, // on window scroll auto fixed position + toolbarIcons : "full", + toolbarTitles : {}, + toolbarHandlers : { + ucwords : function() { + return editormd.toolbarHandlers.ucwords; + }, + lowercase : function() { + return editormd.toolbarHandlers.lowercase; + } }, - department_name: { - required: true - } - }, - messages: { - school_id: { - required: '请选择所属单位' + toolbarCustomIcons : { // using html tag create toolbar icon, unused default tag. + lowercase : "a", + "ucwords" : "Aa" + }, + toolbarIconsClass : { + undo : "fa-undo", + redo : "fa-repeat", + bold : "fa-bold", + del : "fa-strikethrough", + italic : "fa-italic", + quote : "fa-quote-left", + uppercase : "fa-font", + h1 : editormd.classPrefix + "bold", + h2 : editormd.classPrefix + "bold", + h3 : editormd.classPrefix + "bold", + h4 : editormd.classPrefix + "bold", + h5 : editormd.classPrefix + "bold", + h6 : editormd.classPrefix + "bold", + "list-ul" : "fa-list-ul", + "list-ol" : "fa-list-ol", + hr : "fa-minus", + link : "fa-link", + "reference-link" : "fa-anchor", + image : "fa-picture-o", + code : "fa-code", + "preformatted-text" : "fa-file-code-o", + "code-block" : "fa-file-code-o", + table : "fa-table", + datetime : "fa-clock-o", + emoji : "fa-smile-o", + "html-entities" : "fa-copyright", + pagebreak : "fa-newspaper-o", + "goto-line" : "fa-terminal", // fa-crosshairs + watch : "fa-eye-slash", + unwatch : "fa-eye", + preview : "fa-desktop", + search : "fa-search", + fullscreen : "fa-arrows-alt", + clear : "fa-eraser", + help : "fa-question-circle", + info : "fa-info-circle" + }, + toolbarIconTexts : {}, + + lang : { + name : "zh-cn", + description : "开源在线Markdown编辑器
    Open source online Markdown editor.", + tocTitle : "目录", + toolbar : { + undo : "撤销(Ctrl+Z)", + redo : "重做(Ctrl+Y)", + bold : "粗体", + del : "删除线", + italic : "斜体", + quote : "引用", + ucwords : "将每个单词首字母转成大写", + uppercase : "将所选转换成大写", + lowercase : "将所选转换成小写", + h1 : "标题1", + h2 : "标题2", + h3 : "标题3", + h4 : "标题4", + h5 : "标题5", + h6 : "标题6", + "list-ul" : "无序列表", + "list-ol" : "有序列表", + hr : "横线", + link : "链接", + "reference-link" : "引用链接", + image : "添加图片", + code : "行内代码", + "preformatted-text" : "预格式文本 / 代码块(缩进风格)", + "code-block" : "代码块(多语言风格)", + table : "添加表格", + datetime : "日期时间", + emoji : "Emoji表情", + "html-entities" : "HTML实体字符", + pagebreak : "插入分页符", + "goto-line" : "跳转到行", + watch : "关闭实时预览", + unwatch : "开启实时预览", + preview : "全窗口预览HTML(按 Shift + ESC还原)", + fullscreen : "全屏(按ESC还原)", + clear : "清空", + search : "搜索", + help : "使用帮助", + info : "关于" + editormd.title + }, + buttons : { + enter : "确定", + cancel : "取消", + close : "关闭" + }, + dialog : { + link : { + title : "添加链接", + url : "链接地址", + urlTitle : "链接标题", + urlEmpty : "错误:请填写链接地址。" + }, + referenceLink : { + title : "添加引用链接", + name : "引用名称", + url : "链接地址", + urlId : "链接ID", + urlTitle : "链接标题", + nameEmpty: "错误:引用链接的名称不能为空。", + idEmpty : "错误:请填写引用链接的ID。", + urlEmpty : "错误:请填写引用链接的URL地址。" + }, + image : { + title : "添加图片", + url : "图片地址", + link : "图片链接", + alt : "图片描述", + uploadButton : "本地上传", + imageURLEmpty : "错误:图片地址不能为空。", + uploadFileEmpty : "错误:上传的图片不能为空。", + formatNotAllowed : "错误:只允许上传图片文件,允许上传的图片文件格式有:" + }, + preformattedText : { + title : "添加预格式文本或代码块", + emptyAlert : "错误:请填写预格式文本或代码的内容。" + }, + codeBlock : { + title : "添加代码块", + selectLabel : "代码语言:", + selectDefaultText : "请选择代码语言", + otherLanguage : "其他语言", + unselectedLanguageAlert : "错误:请选择代码所属的语言类型。", + codeEmptyAlert : "错误:请填写代码内容。" + }, + htmlEntities : { + title : "HTML 实体字符" + }, + help : { + title : "使用帮助" + } + } } - } - }); - - // modal ready fire - $modal.on('show.bs.modal', function () { - $departmentNameInput.val(''); - $schoolSelect.select2('val', ' '); - }); - - // ************** 学校选择 ************* - var matcherFunc = function(params, data){ - if ($.trim(params.term) === '') { - return data; - } - if (typeof data.text === 'undefined') { - return null; - } - - if (data.name && data.name.indexOf(params.term) > -1) { - var modifiedData = $.extend({}, data, true); - return modifiedData; - } - - // Return `null` if the term should not be displayed - return null; + }; + + editormd.classNames = { + tex : editormd.classPrefix + "tex" }; - var defineSchoolSelect = function(schools) { - $schoolSelect.select2({ - theme: 'bootstrap4', - placeholder: '请选择所属单位', - minimumInputLength: 1, - data: schools, - templateResult: function (item) { - if(!item.id || item.id === '') return item.text; - return item.name; - }, - templateSelection: function(item){ - if (item.id) { - $('#school_id').val(item.id); - } - return item.name || item.text; + editormd.dialogZindex = 99999; + + editormd.$katex = null; + editormd.$marked = null; + editormd.$CodeMirror = null; + editormd.$prettyPrint = null; + + var timer, flowchartTimer; + + editormd.prototype = editormd.fn = { + state : { + watching : false, + loaded : false, + preview : false, + fullscreen : false }, - matcher: matcherFunc - }); - } + + /** + * 构造函数/实例初始化 + * Constructor / instance initialization + * + * @param {String} id 编辑器的ID + * @param {Object} [options={}] 配置选项 Key/Value + * @returns {editormd} 返回editormd的实例对象 + */ + + init : function (id, options) { + + options = options || {}; + + if (typeof id === "object") + { + options = id; + } + + var _this = this; + var classPrefix = this.classPrefix = editormd.classPrefix; + var settings = this.settings = $.extend(true, editormd.defaults, options); + + id = (typeof id === "object") ? settings.id : id; + + var editor = this.editor = $("#" + id); + + this.id = id; + this.lang = settings.lang; + + var classNames = this.classNames = { + textarea : { + html : classPrefix + "html-textarea", + markdown : classPrefix + "markdown-textarea" + } + }; + + settings.pluginPath = (settings.pluginPath === "") ? settings.path + "../plugins/" : settings.pluginPath; + + this.state.watching = (settings.watch) ? true : false; + + if ( !editor.hasClass("editormd") ) { + editor.addClass("editormd"); + } + + editor.css({ + width : (typeof settings.width === "number") ? settings.width + "px" : settings.width, + height : (typeof settings.height === "number") ? settings.height + "px" : settings.height + }); + + if (settings.autoHeight) + { + editor.css("height", "auto"); + } + + var markdownTextarea = this.markdownTextarea = editor.children("textarea"); + + if (markdownTextarea.length < 1) + { + editor.append(""); + markdownTextarea = this.markdownTextarea = editor.children("textarea"); + } + + markdownTextarea.addClass(classNames.textarea.markdown).attr("placeholder", settings.placeholder); + + if (typeof markdownTextarea.attr("name") === "undefined" || markdownTextarea.attr("name") === "") + { + markdownTextarea.attr("name", (settings.name !== "") ? settings.name : id + "-markdown-doc"); + } + + var appendElements = [ + (!settings.readOnly) ? "" : "", + ( (settings.saveHTMLToTextarea) ? "" : "" ), + "
    ", + "
    ", + "
    " + ].join("\n"); + + editor.append(appendElements).addClass(classPrefix + "vertical"); + + if (settings.theme !== "") + { + editor.addClass(classPrefix + "theme-" + settings.theme); + } + + this.mask = editor.children("." + classPrefix + "mask"); + this.containerMask = editor.children("." + classPrefix + "container-mask"); + + if (settings.markdown !== "") + { + markdownTextarea.val(settings.markdown); + } + + if (settings.appendMarkdown !== "") + { + markdownTextarea.val(markdownTextarea.val() + settings.appendMarkdown); + } + + this.htmlTextarea = editor.children("." + classNames.textarea.html); + this.preview = editor.children("." + classPrefix + "preview"); + this.previewContainer = this.preview.children("." + classPrefix + "preview-container"); + + if (settings.previewTheme !== "") + { + this.preview.addClass(classPrefix + "preview-theme-" + settings.previewTheme); + } + + if (typeof define === "function" && define.amd) + { + if (typeof katex !== "undefined") + { + editormd.$katex = katex; + } + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(settings.path + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(settings.path + "codemirror/addon/search/matchesonscrollbar"); + } + } + + if ((typeof define === "function" && define.amd) || !settings.autoLoadModules) + { + if (typeof CodeMirror !== "undefined") { + editormd.$CodeMirror = CodeMirror; + } + + if (typeof marked !== "undefined") { + editormd.$marked = marked; + } + + this.setCodeMirror().setToolbar().loadedDisplay(); + } + else + { + this.loadQueues(); + } - $.ajax({ - url: '/api/schools/for_option.json', - dataType: 'json', - type: 'GET', - success: function(data) { - defineSchoolSelect(data.schools); - } - }); + return this; + }, + + /** + * 所需组件加载队列 + * Required components loading queue + * + * @returns {editormd} 返回editormd的实例对象 + */ + + loadQueues : function() { + var _this = this; + var settings = this.settings; + var loadPath = settings.path; + + var loadFlowChartOrSequenceDiagram = function() { + + if (editormd.isIE8) + { + _this.loadedDisplay(); + + return ; + } - $modal.on('click', '.submit-btn', function(){ - $form.find('.error').html(''); + if (settings.flowChart || settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "raphael.min", function() { - if ($form.valid()) { - var url = $form.data('url'); + editormd.loadScript(loadPath + "underscore.min", function() { - $.ajax({ - method: 'POST', - dataType: 'json', - url: url, - data: $form.serialize(), - success: function(){ - $.notify({ message: '创建成功' }); - $modal.modal('hide'); + if (!settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + } + else if (settings.flowChart && !settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + _this.loadedDisplay(); + }); + }); + } + else if (settings.flowChart && settings.sequenceDiagram) + { + editormd.loadScript(loadPath + "flowchart.min", function() { + editormd.loadScript(loadPath + "jquery.flowchart.min", function() { + editormd.loadScript(loadPath + "sequence-diagram.min", function() { + _this.loadedDisplay(); + }); + }); + }); + } + }); - setTimeout(function(){ - window.location.reload(); - }, 500); - }, - error: function(res){ - var data = res.responseJSON; - $form.find('.error').html(data.message); - } - }); - } - }); + }); + } + else + { + _this.loadedDisplay(); + } + }; - // ============= 添加部门管理员 ============== - var $addMemberModal = $('.admin-add-department-member-modal'); - var $addMemberForm = $addMemberModal.find('.admin-add-department-member-form'); - var $memberSelect = $addMemberModal.find('.department-member-select'); - var $departmentIdInput = $addMemberForm.find('input[name="department_id"]') + editormd.loadCSS(loadPath + "codemirror/codemirror.min"); + + if (settings.searchReplace && !settings.readOnly) + { + editormd.loadCSS(loadPath + "codemirror/addon/dialog/dialog"); + editormd.loadCSS(loadPath + "codemirror/addon/search/matchesonscrollbar"); + } + + if (settings.codeFold) + { + editormd.loadCSS(loadPath + "codemirror/addon/fold/foldgutter"); + } + + editormd.loadScript(loadPath + "codemirror/codemirror.min", function() { + editormd.$CodeMirror = CodeMirror; + + editormd.loadScript(loadPath + "codemirror/modes.min", function() { + + editormd.loadScript(loadPath + "codemirror/addons.min", function() { + + _this.setCodeMirror(); + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + _this.loadedDisplay(); + + return false; + } + + _this.setToolbar(); - $addMemberModal.on('show.bs.modal', function(event){ - var $link = $(event.relatedTarget); - var departmentId = $link.data('department-id'); - $departmentIdInput.val(departmentId); + editormd.loadScript(loadPath + "marked.min", function() { - $memberSelect.select2('val', ' '); - }); + editormd.$marked = marked; + + if (settings.previewCodeHighlight) + { + editormd.loadScript(loadPath + "prettify.min", function() { + loadFlowChartOrSequenceDiagram(); + }); + } + else + { + loadFlowChartOrSequenceDiagram(); + } + }); + + }); + + }); + + }); - $memberSelect.select2({ - theme: 'bootstrap4', - placeholder: '请输入要添加的管理员姓名', - multiple: true, - minimumInputLength: 1, - ajax: { - delay: 500, - url: '/admins/users', - dataType: 'json', - data: function(params){ - return { name: params.term }; + return this; }, - processResults: function(data){ - return { results: data.users } - } - }, - templateResult: function (item) { - if(!item.id || item.id === '') return item.text; - return item.real_name; - }, - templateSelection: function(item){ - if (item.id) { - } - return item.real_name || item.text; - } - }); - - $addMemberModal.on('click', '.submit-btn', function(){ - $addMemberForm.find('.error').html(''); - - var departmentId = $departmentIdInput.val(); - var memberIds = $memberSelect.val(); - if (departmentId && memberIds && memberIds.length > 0) { - $.ajax({ - method: 'POST', - dataType: 'script', - url: '/admins/departments/' + departmentId + '/department_member', - data: { user_ids: memberIds } - }); - } else { - $addMemberModal.modal('hide'); - } - }); - } -}); -$(document).on('turbolinks:load', function() { - if ($('body.admins-identity-authentications-index-page').length > 0) { - var $searchFrom = $('.identity-authentication-list-form'); - $searchFrom.find('select[name="status"]').val('pending'); - - $searchFrom.on('click', '.search-form-tab', function(){ - var $link = $(this); - - $searchFrom.find('input[name="keyword"]').val(''); - $searchFrom.find('select[name="status"]').val('processed'); - - if($link.data('value') === 'processed'){ - $searchFrom.find('.status-filter').show(); - } else { - $searchFrom.find('.status-filter').hide(); - $searchFrom.find('select[name="status"]').val('pending'); - } - }); - } -}) -; + + /** + * 设置 Editor.md 的整体主题,主要是工具栏 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setTheme : function(theme) { + var editor = this.editor; + var oldTheme = this.settings.theme; + var themePrefix = this.classPrefix + "theme-"; + + editor.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.theme = theme; + + return this; + }, + + /** + * 设置 CodeMirror(编辑区)的主题 + * Setting CodeMirror (Editor area) theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setEditorTheme : function(theme) { + var settings = this.settings; + settings.editorTheme = theme; + + if (theme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + this.cm.setOption("theme", theme); + + return this; + }, + + /** + * setEditorTheme() 的别名 + * setEditorTheme() alias + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorTheme : function (theme) { + this.setEditorTheme(theme); + + return this; + }, + + /** + * 设置 Editor.md 的主题 + * Setting Editor.md theme + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setPreviewTheme : function(theme) { + var preview = this.preview; + var oldTheme = this.settings.previewTheme; + var themePrefix = this.classPrefix + "preview-theme-"; + + preview.removeClass(themePrefix + oldTheme).addClass(themePrefix + theme); + + this.settings.previewTheme = theme; + + return this; + }, + + /** + * 配置和初始化CodeMirror组件 + * CodeMirror initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirror : function() { + var settings = this.settings; + var editor = this.editor; + + if (settings.editorTheme !== "default") + { + editormd.loadCSS(settings.path + "codemirror/theme/" + settings.editorTheme); + } + + var codeMirrorConfig = { + mode : settings.mode, + theme : settings.editorTheme, + tabSize : settings.tabSize, + dragDrop : false, + autofocus : settings.autoFocus, + autoCloseTags : settings.autoCloseTags, + readOnly : (settings.readOnly) ? "nocursor" : false, + indentUnit : settings.indentUnit, + lineNumbers : settings.lineNumbers, + lineWrapping : settings.lineWrapping, + extraKeys : { + "Ctrl-Q": function(cm) { + cm.foldCode(cm.getCursor()); + } + }, + foldGutter : settings.codeFold, + gutters : ["CodeMirror-linenumbers", "CodeMirror-foldgutter"], + matchBrackets : settings.matchBrackets, + indentWithTabs : settings.indentWithTabs, + styleActiveLine : settings.styleActiveLine, + styleSelectedText : settings.styleSelectedText, + autoCloseBrackets : settings.autoCloseBrackets, + showTrailingSpace : settings.showTrailingSpace, + highlightSelectionMatches : ( (!settings.matchWordHighlight) ? false : { showToken: (settings.matchWordHighlight === "onselected") ? false : /\w/ } ) + }; + + this.codeEditor = this.cm = editormd.$CodeMirror.fromTextArea(this.markdownTextarea[0], codeMirrorConfig); + this.codeMirror = this.cmElement = editor.children(".CodeMirror"); + + if (settings.value !== "") + { + this.cm.setValue(settings.value); + } + + this.codeMirror.css({ + fontSize : settings.fontSize, + width : (!settings.watch) ? "100%" : "50%" + }); + + if (settings.autoHeight) + { + this.codeMirror.css("height", "auto"); + this.cm.setOption("viewportMargin", Infinity); + } + + if (!settings.lineNumbers) + { + this.codeMirror.find(".CodeMirror-gutters").css("border-right", "none"); + } + + return this; + }, + + /** + * 获取CodeMirror的配置选项 + * Get CodeMirror setting options + * + * @returns {Mixed} return CodeMirror setting option value + */ + + getCodeMirrorOption : function(key) { + return this.cm.getOption(key); + }, + + /** + * 配置和重配置CodeMirror的选项 + * CodeMirror setting options / resettings + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setCodeMirrorOption : function(key, value) { + + this.cm.setOption(key, value); + + return this; + }, + + /** + * 添加 CodeMirror 键盘快捷键 + * Add CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + addKeyMap : function(map, bottom) { + this.cm.addKeyMap(map, bottom); + + return this; + }, + + /** + * 移除 CodeMirror 键盘快捷键 + * Remove CodeMirror keyboard shortcuts key map + * + * @returns {editormd} 返回editormd的实例对象 + */ + + removeKeyMap : function(map) { + this.cm.removeKeyMap(map); + + return this; + }, + + /** + * 跳转到指定的行 + * Goto CodeMirror line + * + * @param {String|Intiger} line line number or "first"|"last" + * @returns {editormd} 返回editormd的实例对象 + */ + + gotoLine : function (line) { + + var settings = this.settings; + + if (!settings.gotoLine) + { + return this; + } + + var cm = this.cm; + var editor = this.editor; + var count = cm.lineCount(); + var preview = this.preview; + + if (typeof line === "string") + { + if(line === "last") + { + line = count; + } + + if (line === "first") + { + line = 1; + } + } + + if (typeof line !== "number") + { + alert("Error: The line number must be an integer."); + return this; + } + + line = parseInt(line) - 1; + + if (line > count) + { + alert("Error: The line number range 1-" + count); + + return this; + } + + cm.setCursor( {line : line, ch : 0} ); + + var scrollInfo = cm.getScrollInfo(); + var clientHeight = scrollInfo.clientHeight; + var coords = cm.charCoords({line : line, ch : 0}, "local"); + + cm.scrollTo(null, (coords.top + coords.bottom - clientHeight) / 2); + + if (settings.watch) + { + var cmScroll = this.codeMirror.find(".CodeMirror-scroll")[0]; + var height = $(cmScroll).height(); + var scrollTop = cmScroll.scrollTop; + var percent = (scrollTop / cmScroll.scrollHeight); + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= cmScroll.scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop(preview[0].scrollHeight * percent); + } + } + + cm.focus(); + + return this; + }, + + /** + * 扩展当前实例对象,可同时设置多个或者只设置一个 + * Extend editormd instance object, can mutil setting. + * + * @returns {editormd} this(editormd instance object.) + */ + + extend : function() { + if (typeof arguments[1] !== "undefined") + { + if (typeof arguments[1] === "function") + { + arguments[1] = $.proxy(arguments[1], this); + } + + this[arguments[0]] = arguments[1]; + } + + if (typeof arguments[0] === "object" && typeof arguments[0].length === "undefined") + { + $.extend(true, this, arguments[0]); + } + + return this; + }, + + /** + * 设置或扩展当前实例对象,单个设置 + * Extend editormd instance object, one by one + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + set : function (key, value) { + + if (typeof value !== "undefined" && typeof value === "function") + { + value = $.proxy(value, this); + } + + this[key] = value; + + return this; + }, + + /** + * 重新配置 + * Resetting editor options + * + * @param {String|Object} key option key + * @param {String|Object} value option value + * @returns {editormd} this(editormd instance object.) + */ + + config : function(key, value) { + var settings = this.settings; + + if (typeof key === "object") + { + settings = $.extend(true, settings, key); + } + + if (typeof key === "string") + { + settings[key] = value; + } + + this.settings = settings; + this.recreate(); + + return this; + }, + + /** + * 注册事件处理方法 + * Bind editor event handle + * + * @param {String} eventType event type + * @param {Function} callback 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + on : function(eventType, callback) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = $.proxy(callback, this); + } + + return this; + }, + + /** + * 解除事件处理方法 + * Unbind editor event handle + * + * @param {String} eventType event type + * @returns {editormd} this(editormd instance object.) + */ + + off : function(eventType) { + var settings = this.settings; + + if (typeof settings["on" + eventType] !== "undefined") + { + settings["on" + eventType] = function(){}; + } + + return this; + }, + + /** + * 显示工具栏 + * Display toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + showToolbar : function(callback) { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + if (settings.toolbar && (this.toolbar.length < 1 || this.toolbar.find("." + this.classPrefix + "menu").html() === "") ) + { + this.setToolbar(); + } + + settings.toolbar = true; + + this.toolbar.show(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 隐藏工具栏 + * Hide toolbar + * + * @param {Function} [callback=function(){}] 回调函数 + * @returns {editormd} this(editormd instance object.) + */ + + hideToolbar : function(callback) { + var settings = this.settings; + + settings.toolbar = false; + this.toolbar.hide(); + this.resize(); + + $.proxy(callback || function(){}, this)(); + + return this; + }, + + /** + * 页面滚动时工具栏的固定定位 + * Set toolbar in window scroll auto fixed position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarAutoFixed : function(fixed) { + + var state = this.state; + var editor = this.editor; + var toolbar = this.toolbar; + var settings = this.settings; + + if (typeof fixed !== "undefined") + { + settings.toolbarAutoFixed = fixed; + } + + var autoFixedHandle = function(){ + var $window = $(window); + var top = $window.scrollTop(); + + if (!settings.toolbarAutoFixed) + { + return false; + } + + if (top - editor.offset().top > 10 && top < editor.height()) + { + toolbar.css({ + position : "fixed", + width : editor.width() + "px", + left : ($window.width() - editor.width()) / 2 + "px" + }); + } + else + { + toolbar.css({ + position : "absolute", + width : "100%", + left : 0 + }); + } + }; + + if (!state.fullscreen && !state.preview && settings.toolbar && settings.toolbarAutoFixed) + { + $(window).bind("scroll", autoFixedHandle); + } + + return this; + }, + + /** + * 配置和初始化工具栏 + * Set toolbar and Initialization + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbar : function() { + var settings = this.settings; + + if(settings.readOnly) { + return this; + } + + var editor = this.editor; + var preview = this.preview; + var classPrefix = this.classPrefix; + + var toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + + if (settings.toolbar && toolbar.length < 1) + { + var toolbarHTML = "
      "; + + editor.append(toolbarHTML); + toolbar = this.toolbar = editor.children("." + classPrefix + "toolbar"); + } + + if (!settings.toolbar) + { + toolbar.hide(); + + return this; + } + + toolbar.show(); + + var icons = (typeof settings.toolbarIcons === "function") ? settings.toolbarIcons() + : ((typeof settings.toolbarIcons === "string") ? editormd.toolbarModes[settings.toolbarIcons] : settings.toolbarIcons); + + var toolbarMenu = toolbar.find("." + this.classPrefix + "menu"), menu = ""; + var pullRight = false; + + for (var i = 0, len = icons.length; i < len; i++) + { + var name = icons[i]; + + if (name === "||") + { + pullRight = true; + } + else if (name === "|") + { + menu += "
    • |
    • "; + } + else + { + var isHeader = (/h(\d)/.test(name)); + var index = name; + + if (name === "watch" && !settings.watch) { + index = "unwatch"; + } + + var title = settings.lang.toolbar[index]; + var iconTexts = settings.toolbarIconTexts[index]; + var iconClass = settings.toolbarIconsClass[index]; + + title = (typeof title === "undefined") ? "" : title; + iconTexts = (typeof iconTexts === "undefined") ? "" : iconTexts; + iconClass = (typeof iconClass === "undefined") ? "" : iconClass; + + var menuItem = pullRight ? "
    • " : "
    • "; + + if (typeof settings.toolbarCustomIcons[name] !== "undefined" && typeof settings.toolbarCustomIcons[name] !== "function") + { + menuItem += settings.toolbarCustomIcons[name]; + } + else + { + menuItem += ""; + menuItem += ""+((isHeader) ? name.toUpperCase() : ( (iconClass === "") ? iconTexts : "") ) + ""; + menuItem += ""; + } + + menuItem += "
    • "; + + menu = pullRight ? menuItem + menu : menu + menuItem; + } + } + + toolbarMenu.html(menu); + + toolbarMenu.find("[title=\"Lowercase\"]").attr("title", settings.lang.toolbar.lowercase); + toolbarMenu.find("[title=\"ucwords\"]").attr("title", settings.lang.toolbar.ucwords); + + this.setToolbarHandler(); + this.setToolbarAutoFixed(); + + return this; + }, + + /** + * 工具栏图标事件处理对象序列 + * Get toolbar icons event handlers + * + * @param {Object} cm CodeMirror的实例对象 + * @param {String} name 要获取的事件处理器名称 + * @returns {Object} 返回处理对象序列 + */ + + dialogLockScreen : function() { + $.proxy(editormd.dialogLockScreen, this)(); + + return this; + }, + + dialogShowMask : function(dialog) { + $.proxy(editormd.dialogShowMask, this)(dialog); + + return this; + }, + + getToolbarHandles : function(name) { + var toolbarHandlers = this.toolbarHandlers = editormd.toolbarHandlers; + + return (name && typeof toolbarIconHandlers[name] !== "undefined") ? toolbarHandlers[name] : toolbarHandlers; + }, + + /** + * 工具栏图标事件处理器 + * Bind toolbar icons event handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + setToolbarHandler : function() { + var _this = this; + var settings = this.settings; + + if (!settings.toolbar || settings.readOnly) { + return this; + } + + var toolbar = this.toolbar; + var cm = this.cm; + var classPrefix = this.classPrefix; + var toolbarIcons = this.toolbarIcons = toolbar.find("." + classPrefix + "menu > li > a"); + var toolbarIconHandlers = this.getToolbarHandles(); + + toolbarIcons.bind(editormd.mouseOrTouch("click", "touchend"), function(event) { + + var icon = $(this).children(".fa"); + var name = icon.attr("name"); + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (name === "") { + return ; + } + + _this.activeIcon = icon; + + if (typeof toolbarIconHandlers[name] !== "undefined") + { + $.proxy(toolbarIconHandlers[name], _this)(cm); + } + else + { + if (typeof settings.toolbarHandlers[name] !== "undefined") + { + $.proxy(settings.toolbarHandlers[name], _this)(cm, icon, cursor, selection); + } + } + + if (name !== "link" && name !== "reference-link" && name !== "image" && name !== "code-block" && + name !== "preformatted-text" && name !== "watch" && name !== "preview" && name !== "search" && name !== "fullscreen" && name !== "info") + { + cm.focus(); + } + + return false; + + }); + + return this; + }, + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + createDialog : function(options) { + return $.proxy(editormd.createDialog, this)(options); + }, + + /** + * 创建关于Editor.md的对话框 + * Create about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + createInfoDialog : function() { + var _this = this; + var editor = this.editor; + var classPrefix = this.classPrefix; + + var infoDialogHTML = [ + "
      ", + "
      ", + "

      " + editormd.title + "v" + editormd.version + "

      ", + "

      " + this.lang.description + "

      ", + "

      " + editormd.homePage + "

      ", + "

      Copyright © 2015 Pandao, The MIT License.

      ", + "
      ", + "", + "
      " + ].join("\n"); + + editor.append(infoDialogHTML); + + var infoDialog = this.infoDialog = editor.children("." + classPrefix + "dialog-info"); + + infoDialog.find("." + classPrefix + "dialog-close").bind(editormd.mouseOrTouch("click", "touchend"), function() { + _this.hideInfoDialog(); + }); + + infoDialog.css("border", (editormd.isIE8) ? "1px solid #ddd" : "").css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 关于Editor.md对话居中定位 + * Editor.md dialog position handle + * + * @returns {editormd} 返回editormd的实例对象 + */ + + infoDialogPosition : function() { + var infoDialog = this.infoDialog; + + var _infoDialogPosition = function() { + infoDialog.css({ + top : ($(window).height() - infoDialog.height()) / 2 + "px", + left : ($(window).width() - infoDialog.width()) / 2 + "px" + }); + }; + + _infoDialogPosition(); + + $(window).resize(_infoDialogPosition); + + return this; + }, + + /** + * 显示关于Editor.md + * Display about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + showInfoDialog : function() { + + $("html,body").css("overflow-x", "hidden"); + + var _this = this; + var editor = this.editor; + var settings = this.settings; + var infoDialog = this.infoDialog = editor.children("." + this.classPrefix + "dialog-info"); + + if (infoDialog.length < 1) + { + this.createInfoDialog(); + } + + this.lockScreen(true); + + this.mask.css({ + opacity : settings.dialogMaskOpacity, + backgroundColor : settings.dialogMaskBgColor + }).show(); + + infoDialog.css("z-index", editormd.dialogZindex).show(); + + this.infoDialogPosition(); + + return this; + }, + + /** + * 隐藏关于Editor.md + * Hide about Editor.md dialog + * + * @returns {editormd} 返回editormd的实例对象 + */ + + hideInfoDialog : function() { + $("html,body").css("overflow-x", ""); + this.infoDialog.hide(); + this.mask.hide(); + this.lockScreen(false); + + return this; + }, + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {editormd} 返回editormd的实例对象 + */ + + lockScreen : function(lock) { + editormd.lockScreen(lock); + this.resize(); + + return this; + }, + + /** + * 编辑器界面重建,用于动态语言包或模块加载等 + * Recreate editor + * + * @returns {editormd} 返回editormd的实例对象 + */ + + recreate : function() { + var _this = this; + var editor = this.editor; + var settings = this.settings; + + this.codeMirror.remove(); + + this.setCodeMirror(); + + if (!settings.readOnly) + { + if (editor.find(".editormd-dialog").length > 0) { + editor.find(".editormd-dialog").remove(); + } + + if (settings.toolbar) + { + this.getToolbarHandles(); + this.setToolbar(); + } + } + + this.loadedDisplay(true); + + return this; + }, + + /** + * 高亮预览HTML的pre代码部分 + * highlight of preview codes + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewCodeHighlight : function() { + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (settings.previewCodeHighlight) + { + previewContainer.find("pre").addClass("prettyprint linenums"); + + if (typeof prettyPrint !== "undefined") + { + prettyPrint(); + } + } + + return this; + }, + + /** + * 解析TeX(KaTeX)科学公式 + * TeX(KaTeX) Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + katexRender : function() { + + if (timer === null) + { + return this; + } + + this.previewContainer.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + editormd.$katex.render(tex.text(), tex[0]); + + tex.find(".katex").css("font-size", "1.6em"); + }); + + return this; + }, + + /** + * 解析和渲染流程图及时序图 + * FlowChart and SequenceDiagram Renderer + * + * @returns {editormd} 返回editormd的实例对象 + */ + + flowChartAndSequenceDiagramRender : function() { + var $this = this; + var settings = this.settings; + var previewContainer = this.previewContainer; + + if (editormd.isIE8) { + return this; + } + + if (settings.flowChart) { + if (flowchartTimer === null) { + return this; + } + + previewContainer.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + previewContainer.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + + var preview = $this.preview; + var codeMirror = $this.codeMirror; + var codeView = codeMirror.find(".CodeMirror-scroll"); + + var height = codeView.height(); + var scrollTop = codeView.scrollTop(); + var percent = (scrollTop / codeView[0].scrollHeight); + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= codeView[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + return this; + }, + + /** + * 注册键盘快捷键处理 + * Register CodeMirror keyMaps (keyboard shortcuts). + * + * @param {Object} keyMap KeyMap key/value {"(Ctrl/Shift/Alt)-Key" : function(){}} + * @returns {editormd} return this + */ + + registerKeyMaps : function(keyMap) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + var toolbarHandlers = editormd.toolbarHandlers; + var disabledKeyMaps = settings.disabledKeyMaps; + + keyMap = keyMap || null; + + if (keyMap) + { + for (var i in keyMap) + { + if ($.inArray(i, disabledKeyMaps) < 0) + { + var map = {}; + map[i] = keyMap[i]; + + cm.addKeyMap(keyMap); + } + } + } + else + { + for (var k in editormd.keyMaps) + { + var _keyMap = editormd.keyMaps[k]; + var handle = (typeof _keyMap === "string") ? $.proxy(toolbarHandlers[_keyMap], _this) : $.proxy(_keyMap, _this); + + if ($.inArray(k, ["F9", "F10", "F11"]) < 0 && $.inArray(k, disabledKeyMaps) < 0) + { + var _map = {}; + _map[k] = handle; + + cm.addKeyMap(_map); + } + } + + $(window).keydown(function(event) { + + var keymaps = { + "120" : "F9", + "121" : "F10", + "122" : "F11" + }; + + if ( $.inArray(keymaps[event.keyCode], disabledKeyMaps) < 0 ) + { + switch (event.keyCode) + { + case 120: + $.proxy(toolbarHandlers["watch"], _this)(); + return false; + break; + + case 121: + $.proxy(toolbarHandlers["preview"], _this)(); + return false; + break; + + case 122: + $.proxy(toolbarHandlers["fullscreen"], _this)(); + return false; + break; + + default: + break; + } + } + }); + } + + return this; + }, + + /** + * 绑定同步滚动 + * + * @returns {editormd} return this + */ + + bindScrollEvent : function() { + + var _this = this; + var preview = this.preview; + var settings = this.settings; + var codeMirror = this.codeMirror; + var mouseOrTouch = editormd.mouseOrTouch; + + if (!settings.syncScrolling) { + return this; + } + + var cmBindScroll = function() { + codeMirror.find(".CodeMirror-scroll").bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + + var tocHeight = 0; + + preview.find(".markdown-toc-list").each(function(){ + tocHeight += $(this).height(); + }); + + var tocMenuHeight = preview.find(".editormd-toc-menu").height(); + tocMenuHeight = (!tocMenuHeight) ? 0 : tocMenuHeight; + + if (scrollTop === 0) + { + preview.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight - 16) + { + preview.scrollTop(preview[0].scrollHeight); + } + else + { + preview.scrollTop((preview[0].scrollHeight + tocHeight + tocMenuHeight) * percent); + } + + $.proxy(settings.onscroll, _this)(event); + }); + }; + + var cmUnbindScroll = function() { + codeMirror.find(".CodeMirror-scroll").unbind(mouseOrTouch("scroll", "touchmove")); + }; + + var previewBindScroll = function() { + + preview.bind(mouseOrTouch("scroll", "touchmove"), function(event) { + var height = $(this).height(); + var scrollTop = $(this).scrollTop(); + var percent = (scrollTop / $(this)[0].scrollHeight); + var codeView = codeMirror.find(".CodeMirror-scroll"); + + if(scrollTop === 0) + { + codeView.scrollTop(0); + } + else if (scrollTop + height >= $(this)[0].scrollHeight) + { + codeView.scrollTop(codeView[0].scrollHeight); + } + else + { + codeView.scrollTop(codeView[0].scrollHeight * percent); + } + + $.proxy(settings.onpreviewscroll, _this)(event); + }); + + }; + + var previewUnbindScroll = function() { + preview.unbind(mouseOrTouch("scroll", "touchmove")); + }; + + codeMirror.bind({ + mouseover : cmBindScroll, + mouseout : cmUnbindScroll, + touchstart : cmBindScroll, + touchend : cmUnbindScroll + }); + + if (settings.syncScrolling === "single") { + return this; + } + + preview.bind({ + mouseover : previewBindScroll, + mouseout : previewUnbindScroll, + touchstart : previewBindScroll, + touchend : previewUnbindScroll + }); + + return this; + }, + + bindChangeEvent : function() { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + if (!settings.syncScrolling) { + return this; + } + + cm.on("change", function(_cm, changeObj) { + + if (settings.watch) + { + _this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + } + + timer = setTimeout(function() { + clearTimeout(timer); + _this.save(); + timer = null; + }, settings.delay); + }); + + return this; + }, + + /** + * 加载队列完成之后的显示处理 + * Display handle of the module queues loaded after. + * + * @param {Boolean} recreate 是否为重建编辑器 + * @returns {editormd} 返回editormd的实例对象 + */ + + loadedDisplay : function(recreate) { + + recreate = recreate || false; + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var settings = this.settings; + + this.containerMask.hide(); + + this.save(); + + if (settings.watch) { + preview.show(); + } + + editor.data("oldWidth", editor.width()).data("oldHeight", editor.height()); // 为了兼容Zepto + + this.resize(); + this.registerKeyMaps(); + + $(window).resize(function(){ + _this.resize(); + }); + + this.bindScrollEvent().bindChangeEvent(); + + if (!recreate) + { + $.proxy(settings.onload, this)(); + } + + this.state.loaded = true; + + return this; + }, + + /** + * 设置编辑器的宽度 + * Set editor width + * + * @param {Number|String} width 编辑器宽度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + width : function(width) { + + this.editor.css("width", (typeof width === "number") ? width + "px" : width); + this.resize(); + + return this; + }, + + /** + * 设置编辑器的高度 + * Set editor height + * + * @param {Number|String} height 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + height : function(height) { + + this.editor.css("height", (typeof height === "number") ? height + "px" : height); + this.resize(); + + return this; + }, + + /** + * 调整编辑器的尺寸和布局 + * Resize editor layout + * + * @param {Number|String} [width=null] 编辑器宽度值 + * @param {Number|String} [height=null] 编辑器高度值 + * @returns {editormd} 返回editormd的实例对象 + */ + + resize : function(width, height) { + + width = width || null; + height = height || null; + + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + + if (width) + { + editor.css("width", (typeof width === "number") ? width + "px" : width); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + editor.css("height", "auto"); + codeMirror.css("height", "auto"); + } + else + { + if (height) + { + editor.css("height", (typeof height === "number") ? height + "px" : height); + } + + if (state.fullscreen) + { + editor.height($(window).height()); + } + + if (settings.toolbar && !settings.readOnly) + { + codeMirror.css("margin-top", toolbar.height() + 1).height(editor.height() - toolbar.height()); + } + else + { + codeMirror.css("margin-top", 0).height(editor.height()); + } + } + + if(settings.watch) + { + codeMirror.width(editor.width() / 2); + preview.width((!state.preview) ? editor.width() / 2 : editor.width()); + + this.previewContainer.css("padding", settings.autoHeight ? "20px 20px 50px 40px" : "20px"); + + if (settings.toolbar && !settings.readOnly) + { + preview.css("top", toolbar.height() + 1); + } + else + { + preview.css("top", 0); + } + + if (settings.autoHeight && !state.fullscreen && !state.preview) + { + preview.height(""); + } + else + { + var previewHeight = (settings.toolbar && !settings.readOnly) ? editor.height() - toolbar.height() : editor.height(); + + preview.height(previewHeight); + } + } + else + { + codeMirror.width(editor.width()); + preview.hide(); + } + + if (state.loaded) + { + $.proxy(settings.onresize, this)(); + } + + return this; + }, + + /** + * 解析和保存Markdown代码 + * Parse & Saving Markdown source code + * + * @returns {editormd} 返回editormd的实例对象 + */ + + save : function() { + + if (timer === null) + { + return this; + } + + var _this = this; + var state = this.state; + var settings = this.settings; + var cm = this.cm; + var cmValue = cm.getValue(); + var previewContainer = this.previewContainer; + + if (settings.mode !== "gfm" && settings.mode !== "markdown") + { + this.markdownTextarea.val(cmValue); + + return this; + } + + var marked = editormd.$marked; + var markdownToC = this.markdownToC = []; + var rendererOptions = this.markedRendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + pageBreak : settings.pageBreak, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = this.markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : true, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 关闭忽略HTML标签,即开启识别HTML标签,默认为false + smartLists : true, + smartypants : true + }; + + marked.setOptions(markedOptions); + + var newMarkdownDoc = editormd.$marked(cmValue, markedOptions); + + //console.info("cmValue", cmValue, newMarkdownDoc); + + newMarkdownDoc = editormd.filterHTMLTags(newMarkdownDoc, settings.htmlDecode); + + //console.error("cmValue", cmValue, newMarkdownDoc); + + this.markdownTextarea.text(cmValue); + + cm.save(); + + if (settings.saveHTMLToTextarea) + { + this.htmlTextarea.text(newMarkdownDoc); + } + + if(settings.watch || (!settings.watch && state.preview)) + { + previewContainer.html(newMarkdownDoc); + + this.previewCodeHighlight(); + + if (settings.toc) + { + var tocContainer = (settings.tocContainer === "") ? previewContainer : $(settings.tocContainer); + var tocMenu = tocContainer.find("." + this.classPrefix + "toc-menu"); + + tocContainer.attr("previewContainer", (settings.tocContainer === "") ? "true" : "false"); + + if (settings.tocContainer !== "" && tocMenu.length > 0) + { + tocMenu.remove(); + } + + editormd.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || tocContainer.find("." + this.classPrefix + "toc-menu").length > 0) + { + editormd.tocDropdownMenu(tocContainer, (settings.tocTitle !== "") ? settings.tocTitle : this.lang.tocTitle); + } + + if (settings.tocContainer !== "") + { + previewContainer.find(".markdown-toc").css("border", "none"); + } + } + + if (settings.tex) + { + if (!editormd.kaTeXLoaded && settings.autoLoadModules) + { + editormd.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + _this.katexRender(); + }); + } + else + { + editormd.$katex = katex; + this.katexRender(); + } + } + + if (settings.flowChart || settings.sequenceDiagram) + { + flowchartTimer = setTimeout(function(){ + clearTimeout(flowchartTimer); + _this.flowChartAndSequenceDiagramRender(); + flowchartTimer = null; + }, 10); + } + + if (state.loaded) + { + $.proxy(settings.onchange, this)(); + } + } + + return this; + }, + + /** + * 聚焦光标位置 + * Focusing the cursor position + * + * @returns {editormd} 返回editormd的实例对象 + */ + + focus : function() { + this.cm.focus(); + + return this; + }, + + /** + * 设置光标的位置 + * Set cursor position + * + * @param {Object} cursor 要设置的光标位置键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setCursor : function(cursor) { + this.cm.setCursor(cursor); + + return this; + }, + + /** + * 获取当前光标的位置 + * Get the current position of the cursor + * + * @returns {Cursor} 返回一个光标Cursor对象 + */ + + getCursor : function() { + return this.cm.getCursor(); + }, + + /** + * 设置光标选中的范围 + * Set cursor selected ranges + * + * @param {Object} from 开始位置的光标键值对象,例:{line:1, ch:0} + * @param {Object} to 结束位置的光标键值对象,例:{line:1, ch:0} + * @returns {editormd} 返回editormd的实例对象 + */ + + setSelection : function(from, to) { + + this.cm.setSelection(from, to); + + return this; + }, + + /** + * 获取光标选中的文本 + * Get the texts from cursor selected + * + * @returns {String} 返回选中文本的字符串形式 + */ + + getSelection : function() { + return this.cm.getSelection(); + }, + + /** + * 设置光标选中的文本范围 + * Set the cursor selection ranges + * + * @param {Array} ranges cursor selection ranges array + * @returns {Array} return this + */ + + setSelections : function(ranges) { + this.cm.setSelections(ranges); + + return this; + }, + + /** + * 获取光标选中的文本范围 + * Get the cursor selection ranges + * + * @returns {Array} return selection ranges array + */ + + getSelections : function() { + return this.cm.getSelections(); + }, + + /** + * 替换当前光标选中的文本或在当前光标处插入新字符 + * Replace the text at the current cursor selected or insert a new character at the current cursor position + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + replaceSelection : function(value) { + this.cm.replaceSelection(value); + + return this; + }, + + /** + * 在当前光标处插入新字符 + * Insert a new character at the current cursor position + * + * 同replaceSelection()方法 + * With the replaceSelection() method + * + * @param {String} value 要插入的字符值 + * @returns {editormd} 返回editormd的实例对象 + */ + + insertValue : function(value) { + this.replaceSelection(value); + + return this; + }, + + /** + * 追加markdown + * append Markdown to editor + * + * @param {String} md 要追加的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + appendMarkdown : function(md) { + var settings = this.settings; + var cm = this.cm; + + cm.setValue(cm.getValue() + md); + + return this; + }, + + /** + * 设置和传入编辑器的markdown源文档 + * Set Markdown source document + * + * @param {String} md 要传入的markdown源文档 + * @returns {editormd} 返回editormd的实例对象 + */ + + setMarkdown : function(md) { + this.cm.setValue(md || this.settings.markdown); + + return this; + }, + + /** + * 获取编辑器的markdown源文档 + * Set Editor.md markdown/CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getMarkdown : function() { + return this.cm.getValue(); + }, + + /** + * 获取编辑器的源文档 + * Get CodeMirror value + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getValue : function() { + return this.cm.getValue(); + }, + + /** + * 设置编辑器的源文档 + * Set CodeMirror value + * + * @param {String} value set code/value/string/text + * @returns {editormd} 返回editormd的实例对象 + */ + + setValue : function(value) { + this.cm.setValue(value); + + return this; + }, + + /** + * 清空编辑器 + * Empty CodeMirror editor container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + clear : function() { + this.cm.setValue(""); + + return this; + }, + + /** + * 获取解析后存放在Textarea的HTML源码 + * Get parsed html code from Textarea + * + * @returns {String} 返回HTML源码 + */ + + getHTML : function() { + if (!this.settings.saveHTMLToTextarea) + { + alert("Error: settings.saveHTMLToTextarea == false"); + + return false; + } + + return this.htmlTextarea.val(); + }, + + /** + * getHTML()的别名 + * getHTML (alias) + * + * @returns {String} Return html code 返回HTML源码 + */ + + getTextareaSavedHTML : function() { + return this.getHTML(); + }, + + /** + * 获取预览窗口的HTML源码 + * Get html from preview container + * + * @returns {editormd} 返回editormd的实例对象 + */ + + getPreviewedHTML : function() { + if (!this.settings.watch) + { + alert("Error: settings.watch == false"); + + return false; + } + + return this.previewContainer.html(); + }, + + /** + * 开启实时预览 + * Enable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + watch : function(callback) { + var settings = this.settings; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) + { + return this; + } + + this.state.watching = settings.watch = true; + this.preview.show(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.watch); + icon.removeClass(unWatchIcon).addClass(watchIcon); + } + + this.codeMirror.css("border-right", "1px solid #ddd").width(this.editor.width() / 2); + + timer = 0; + + this.save().resize(); + + if (!settings.onwatch) + { + settings.onwatch = callback || function() {}; + } + + $.proxy(settings.onwatch, this)(); + + return this; + }, + + /** + * 关闭实时预览 + * Disable real-time watching + * + * @returns {editormd} 返回editormd的实例对象 + */ + + unwatch : function(callback) { + var settings = this.settings; + this.state.watching = settings.watch = false; + this.preview.hide(); + + if (this.toolbar) + { + var watchIcon = settings.toolbarIconsClass.watch; + var unWatchIcon = settings.toolbarIconsClass.unwatch; + + var icon = this.toolbar.find(".fa[name=watch]"); + icon.parent().attr("title", settings.lang.toolbar.unwatch); + icon.removeClass(watchIcon).addClass(unWatchIcon); + } + + this.codeMirror.css("border-right", "none").width(this.editor.width()); + + this.resize(); + + if (!settings.onunwatch) + { + settings.onunwatch = callback || function() {}; + } + + $.proxy(settings.onunwatch, this)(); + + return this; + }, + + /** + * 显示编辑器 + * Show editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + show : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.show(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器 + * Hide editor + * + * @param {Function} [callback=function()] 回调函数 + * @returns {editormd} 返回editormd的实例对象 + */ + + hide : function(callback) { + callback = callback || function() {}; + + var _this = this; + this.editor.hide(0, function() { + $.proxy(callback, _this)(); + }); + + return this; + }, + + /** + * 隐藏编辑器部分,只预览HTML + * Enter preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewing : function() { + + var _this = this; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var codeMirror = this.codeMirror; + var previewContainer = this.previewContainer; + + if ($.inArray(settings.mode, ["gfm", "markdown"]) < 0) { + return this; + } + + if (settings.toolbar && toolbar) { + toolbar.toggle(); + toolbar.find(".fa[name=preview]").toggleClass("active"); + } + + codeMirror.toggle(); + + var escHandle = function(event) { + if (event.shiftKey && event.keyCode === 27) { + _this.previewed(); + } + }; + + if (codeMirror.css("display") === "none") // 为了兼容Zepto,而不使用codeMirror.is(":hidden") + { + this.state.preview = true; + + if (this.state.fullscreen) { + preview.css("background", "#fff"); + } + + editor.find("." + this.classPrefix + "preview-close-btn").show().bind(editormd.mouseOrTouch("click", "touchend"), function(){ + _this.previewed(); + }); + + if (!settings.watch) + { + this.save(); + } + else + { + previewContainer.css("padding", ""); + } + + previewContainer.addClass(this.classPrefix + "preview-active"); + + preview.show().css({ + position : "", + top : 0, + width : editor.width(), + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewing, this)(); + } + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.previewed(); + } + }, + + /** + * 显示编辑器部分,退出只预览HTML + * Exit preview html state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + previewed : function() { + + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var previewContainer = this.previewContainer; + var previewCloseBtn = editor.find("." + this.classPrefix + "preview-close-btn"); + + this.state.preview = false; + + this.codeMirror.show(); + + if (settings.toolbar) { + toolbar.show(); + } + + preview[(settings.watch) ? "show" : "hide"](); + + previewCloseBtn.hide().unbind(editormd.mouseOrTouch("click", "touchend")); + + previewContainer.removeClass(this.classPrefix + "preview-active"); + + if (settings.watch) + { + previewContainer.css("padding", "20px"); + } + + preview.css({ + background : null, + position : "absolute", + width : editor.width() / 2, + height : (settings.autoHeight && !this.state.fullscreen) ? "auto" : editor.height() - toolbar.height(), + top : (settings.toolbar) ? toolbar.height() : 0 + }); + + if (this.state.loaded) + { + $.proxy(settings.onpreviewed, this)(); + } + + return this; + }, + + /** + * 编辑器全屏显示 + * Fullscreen show + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreen : function() { + + var _this = this; + var state = this.state; + var editor = this.editor; + var preview = this.preview; + var toolbar = this.toolbar; + var settings = this.settings; + var fullscreenClass = this.classPrefix + "fullscreen"; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().toggleClass("active"); + } + + var escHandle = function(event) { + if (!event.shiftKey && event.keyCode === 27) + { + if (state.fullscreen) + { + _this.fullscreenExit(); + } + } + }; + + if (!editor.hasClass(fullscreenClass)) + { + state.fullscreen = true; + + $("html,body").css("overflow", "hidden"); + + editor.css({ + width : $(window).width(), + height : $(window).height() + }).addClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreen, this)(); + + $(window).bind("keyup", escHandle); + } + else + { + $(window).unbind("keyup", escHandle); + this.fullscreenExit(); + } + + return this; + }, + + /** + * 编辑器退出全屏显示 + * Exit fullscreen state + * + * @returns {editormd} 返回editormd的实例对象 + */ + + fullscreenExit : function() { + + var editor = this.editor; + var settings = this.settings; + var toolbar = this.toolbar; + var fullscreenClass = this.classPrefix + "fullscreen"; + + this.state.fullscreen = false; + + if (toolbar) { + toolbar.find(".fa[name=fullscreen]").parent().removeClass("active"); + } + + $("html,body").css("overflow", ""); + + editor.css({ + width : editor.data("oldWidth"), + height : editor.data("oldHeight") + }).removeClass(fullscreenClass); + + this.resize(); + + $.proxy(settings.onfullscreenExit, this)(); + + return this; + }, + + /** + * 加载并执行插件 + * Load and execute the plugin + * + * @param {String} name plugin name / function name + * @param {String} path plugin load path + * @returns {editormd} 返回editormd的实例对象 + */ + + executePlugin : function(name, path) { + + var _this = this; + var cm = this.cm; + var settings = this.settings; + + path = settings.pluginPath + path; + + if (typeof define === "function") + { + if (typeof this[name] === "undefined") + { + alert("Error: " + name + " plugin is not found, you are not load this plugin."); + + return this; + } + + this[name](cm); + + return this; + } + + if ($.inArray(path, editormd.loadFiles.plugin) < 0) + { + editormd.loadPlugin(path, function() { + editormd.loadPlugins[name] = _this[name]; + _this[name](cm); + }); + } + else + { + $.proxy(editormd.loadPlugins[name], this)(cm); + } + + return this; + }, + + /** + * 搜索替换 + * Search & replace + * + * @param {String} command CodeMirror serach commands, "find, fintNext, fintPrev, clearSearch, replace, replaceAll" + * @returns {editormd} return this + */ + + search : function(command) { + var settings = this.settings; + + if (!settings.searchReplace) + { + alert("Error: settings.searchReplace == false"); + return this; + } + + if (!settings.readOnly) + { + this.cm.execCommand(command || "find"); + } + + return this; + }, + + searchReplace : function() { + this.search("replace"); + + return this; + }, + + searchReplaceAll : function() { + this.search("replaceAll"); + + return this; + } + }; + + editormd.fn.init.prototype = editormd.fn; + + /** + * 锁屏 + * lock screen when dialog opening + * + * @returns {void} + */ + + editormd.dialogLockScreen = function() { + var settings = this.settings || {dialogLockScreen : true}; + + if (settings.dialogLockScreen) + { + $("html,body").css("overflow", "hidden"); + this.resize(); + } + }; + + /** + * 显示透明背景层 + * Display mask layer when dialog opening + * + * @param {Object} dialog dialog jQuery object + * @returns {void} + */ + + editormd.dialogShowMask = function(dialog) { + var editor = this.editor; + var settings = this.settings || {dialogShowMask : true}; + + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + + if (settings.dialogShowMask) { + editor.children("." + this.classPrefix + "mask").css("z-index", parseInt(dialog.css("z-index")) - 1).show(); + } + }; + + editormd.toolbarHandlers = { + undo : function() { + this.cm.undo(); + }, + + redo : function() { + this.cm.redo(); + }, + + bold : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("**" + selection + "**"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + del : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("~~" + selection + "~~"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + italic : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("*" + selection + "*"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + quote : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("> " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("> " + selection); + } + + //cm.replaceSelection("> " + selection); + //cm.setCursor(cursor.line, (selection === "") ? cursor.ch + 2 : cursor.ch + selection.length + 2); + }, + + ucfirst : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.firstUpperCase(selection)); + cm.setSelections(selections); + }, + + ucwords : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(editormd.wordsFirstUpperCase(selection)); + cm.setSelections(selections); + }, + + uppercase : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toUpperCase()); + cm.setSelections(selections); + }, + + lowercase : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + var selections = cm.listSelections(); + + cm.replaceSelection(selection.toLowerCase()); + cm.setSelections(selections); + }, + + h1 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("# " + selection); + cm.setCursor(cursor.line, cursor.ch + 2); + } + else + { + cm.replaceSelection("# " + selection); + } + }, + + h2 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("## " + selection); + cm.setCursor(cursor.line, cursor.ch + 3); + } + else + { + cm.replaceSelection("## " + selection); + } + }, + + h3 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("### " + selection); + cm.setCursor(cursor.line, cursor.ch + 4); + } + else + { + cm.replaceSelection("### " + selection); + } + }, + + h4 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("#### " + selection); + cm.setCursor(cursor.line, cursor.ch + 5); + } + else + { + cm.replaceSelection("#### " + selection); + } + }, + + h5 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("##### " + selection); + cm.setCursor(cursor.line, cursor.ch + 6); + } + else + { + cm.replaceSelection("##### " + selection); + } + }, + + h6 : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (cursor.ch !== 0) + { + cm.setCursor(cursor.line, 0); + cm.replaceSelection("###### " + selection); + cm.setCursor(cursor.line, cursor.ch + 7); + } + else + { + cm.replaceSelection("###### " + selection); + } + }, + + "list-ul" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (selection === "") + { + cm.replaceSelection("- " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : "- " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + "list-ol" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if(selection === "") + { + cm.replaceSelection("1. " + selection); + } + else + { + var selectionText = selection.split("\n"); + + for (var i = 0, len = selectionText.length; i < len; i++) + { + selectionText[i] = (selectionText[i] === "") ? "" : (i+1) + ". " + selectionText[i]; + } + + cm.replaceSelection(selectionText.join("\n")); + } + }, + + hr : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(((cursor.ch !== 0) ? "\n\n" : "\n") + "------------\n\n"); + }, + + tex : function() { + if (!this.settings.tex) + { + alert("settings.tex === false"); + return this; + } + + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("$$" + selection + "$$"); + + if(selection === "") { + cm.setCursor(cursor.line, cursor.ch + 2); + } + }, + + link : function() { + this.executePlugin("linkDialog", "link-dialog/link-dialog"); + }, + + "reference-link" : function() { + this.executePlugin("referenceLinkDialog", "reference-link-dialog/reference-link-dialog"); + }, + + pagebreak : function() { + if (!this.settings.pageBreak) + { + alert("settings.pageBreak === false"); + return this; + } + + var cm = this.cm; + var selection = cm.getSelection(); + + cm.replaceSelection("\r\n[========]\r\n"); + }, + + image : function() { + this.executePlugin("imageDialog", "image-dialog/image-dialog"); + }, + + code : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection("`" + selection + "`"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "code-block" : function() { + this.executePlugin("codeBlockDialog", "code-block-dialog/code-block-dialog"); + }, + + "preformatted-text" : function() { + this.executePlugin("preformattedTextDialog", "preformatted-text-dialog/preformatted-text-dialog"); + }, + + table : function() { + this.executePlugin("tableDialog", "table-dialog/table-dialog"); + }, + + datetime : function() { + var cm = this.cm; + var selection = cm.getSelection(); + var date = new Date(); + var langName = this.settings.lang.name; + var datefmt = editormd.dateFormat() + " " + editormd.dateFormat((langName === "zh-cn" || langName === "zh-tw") ? "cn-week-day" : "week-day"); + + cm.replaceSelection(datefmt); + }, + + emoji : function() { + this.executePlugin("emojiDialog", "emoji-dialog/emoji-dialog"); + }, + + "html-entities" : function() { + this.executePlugin("htmlEntitiesDialog", "html-entities-dialog/html-entities-dialog"); + }, + + "goto-line" : function() { + this.executePlugin("gotoLineDialog", "goto-line-dialog/goto-line-dialog"); + }, + + watch : function() { + this[this.settings.watch ? "unwatch" : "watch"](); + }, + + preview : function() { + this.previewing(); + }, + + fullscreen : function() { + this.fullscreen(); + }, + + clear : function() { + this.clear(); + }, + + search : function() { + this.search(); + }, + + help : function() { + this.executePlugin("helpDialog", "help-dialog/help-dialog"); + }, + + info : function() { + this.showInfoDialog(); + } + }; + + editormd.keyMaps = { + "Ctrl-1" : "h1", + "Ctrl-2" : "h2", + "Ctrl-3" : "h3", + "Ctrl-4" : "h4", + "Ctrl-5" : "h5", + "Ctrl-6" : "h6", + "Ctrl-B" : "bold", // if this is string == editormd.toolbarHandlers.xxxx + "Ctrl-D" : "datetime", + + "Ctrl-E" : function() { // emoji + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.emoji) + { + alert("Error: settings.emoji == false"); + return ; + } + + cm.replaceSelection(":" + selection + ":"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-Alt-G" : "goto-line", + "Ctrl-H" : "hr", + "Ctrl-I" : "italic", + "Ctrl-K" : "code", + + "Ctrl-L" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("[" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + "Ctrl-U" : "list-ul", + + "Shift-Ctrl-A" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + if (!this.settings.atLink) + { + alert("Error: settings.atLink == false"); + return ; + } + + cm.replaceSelection("@" + selection); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 1); + } + }, + + "Shift-Ctrl-C" : "code", + "Shift-Ctrl-Q" : "quote", + "Shift-Ctrl-S" : "del", + "Shift-Ctrl-K" : "tex", // KaTeX + + "Shift-Alt-C" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + cm.replaceSelection(["```", selection, "```"].join("\n")); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 3); + } + }, + + "Shift-Ctrl-Alt-C" : "code-block", + "Shift-Ctrl-H" : "html-entities", + "Shift-Alt-H" : "help", + "Shift-Ctrl-E" : "emoji", + "Shift-Ctrl-U" : "uppercase", + "Shift-Alt-U" : "ucwords", + "Shift-Ctrl-Alt-U" : "ucfirst", + "Shift-Alt-L" : "lowercase", + + "Shift-Ctrl-I" : function() { + var cm = this.cm; + var cursor = cm.getCursor(); + var selection = cm.getSelection(); + + var title = (selection === "") ? "" : " \""+selection+"\""; + + cm.replaceSelection("![" + selection + "]("+title+")"); + + if (selection === "") { + cm.setCursor(cursor.line, cursor.ch + 4); + } + }, + + "Shift-Ctrl-Alt-I" : "image", + "Shift-Ctrl-L" : "link", + "Shift-Ctrl-O" : "list-ol", + "Shift-Ctrl-P" : "preformatted-text", + "Shift-Ctrl-T" : "table", + "Shift-Alt-P" : "pagebreak", + "F9" : "watch", + "F10" : "preview", + "F11" : "fullscreen", + }; + + /** + * 清除字符串两边的空格 + * Clear the space of strings both sides. + * + * @param {String} str string + * @returns {String} trimed string + */ + + var trim = function(str) { + return (!String.prototype.trim) ? str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "") : str.trim(); + }; + + editormd.trim = trim; + + /** + * 所有单词首字母大写 + * Words first to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var ucwords = function (str) { + return str.toLowerCase().replace(/\b(\w)|\s(\w)/g, function($1) { + return $1.toUpperCase(); + }); + }; + + editormd.ucwords = editormd.wordsFirstUpperCase = ucwords; + + /** + * 字符串首字母大写 + * Only string first char to uppercase + * + * @param {String} str string + * @returns {String} string + */ + + var firstUpperCase = function(str) { + return str.toLowerCase().replace(/\b(\w)/, function($1){ + return $1.toUpperCase(); + }); + }; + + var ucfirst = firstUpperCase; + + editormd.firstUpperCase = editormd.ucfirst = firstUpperCase; + + editormd.urls = { + atLinkBase : "https://github.com/" + }; + + editormd.regexs = { + atLink : /@(\w+)/g, + email : /(\w+)@(\w+)\.(\w+)\.?(\w+)?/g, + emailLink : /(mailto:)?([\w\.\_]+)@(\w+)\.(\w+)\.?(\w+)?/g, + emoji : /:([\w\+-]+):/g, + emojiDatetime : /(\d{2}:\d{2}:\d{2})/g, + twemoji : /:(tw-([\w]+)-?(\w+)?):/g, + fontAwesome : /:(fa-([\w]+)(-(\w+)){0,}):/g, + editormdLogo : /:(editormd-logo-?(\w+)?):/g, + pageBreak : /^\[[=]{8,}\]$/ + }; + + // Emoji graphics files url path + editormd.emoji = { + path : "http://www.emoji-cheat-sheet.com/graphics/emojis/", + ext : ".png" + }; + + // Twitter Emoji (Twemoji) graphics files url path + editormd.twemoji = { + path : "http://twemoji.maxcdn.com/36x36/", + ext : ".png" + }; + + /** + * 自定义marked的解析器 + * Custom Marked renderer rules + * + * @param {Array} markdownToC 传入用于接收TOC的数组 + * @returns {Renderer} markedRenderer 返回marked的Renderer自定义对象 + */ + + editormd.markedRenderer = function(markdownToC, options) { + var defaults = { + toc : true, // Table of contents + tocm : false, + tocStartLevel : 1, // Said from H1 to create ToC + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + taskList : false, // Enable Github Flavored Markdown task lists + emoji : false, // :emoji: , Support Twemoji, fontAwesome, Editor.md logo emojis. + tex : false, // TeX(LaTeX), based on KaTeX + flowChart : false, // flowChart.js only support IE9+ + sequenceDiagram : false, // sequenceDiagram.js only support IE9+ + }; + + var settings = $.extend(defaults, options || {}); + var marked = editormd.$marked; + var markedRenderer = new marked.Renderer(); + markdownToC = markdownToC || []; + + var regexs = editormd.regexs; + var atLinkReg = regexs.atLink; + var emojiReg = regexs.emoji; + var emailReg = regexs.email; + var emailLinkReg = regexs.emailLink; + var twemojiReg = regexs.twemoji; + var faIconReg = regexs.fontAwesome; + var editormdLogoReg = regexs.editormdLogo; + var pageBreakReg = regexs.pageBreak; + + markedRenderer.emoji = function(text) { + + text = text.replace(editormd.regexs.emojiDatetime, function($1) { + return $1.replace(/:/g, ":"); + }); + + var matchs = text.match(emojiReg); + + if (!matchs || !settings.emoji) { + return text; + } + + for (var i = 0, len = matchs.length; i < len; i++) + { + if (matchs[i] === ":+1:") { + matchs[i] = ":\\+1:"; + } + + text = text.replace(new RegExp(matchs[i]), function($1, $2){ + var faMatchs = $1.match(faIconReg); + var name = $1.replace(/:/g, ""); + + if (faMatchs) + { + for (var fa = 0, len1 = faMatchs.length; fa < len1; fa++) + { + var faName = faMatchs[fa].replace(/:/g, ""); + + return ""; + } + } + else + { + var emdlogoMathcs = $1.match(editormdLogoReg); + var twemojiMatchs = $1.match(twemojiReg); + + if (emdlogoMathcs) + { + for (var x = 0, len2 = emdlogoMathcs.length; x < len2; x++) + { + var logoName = emdlogoMathcs[x].replace(/:/g, ""); + return ""; + } + } + else if (twemojiMatchs) + { + for (var t = 0, len3 = twemojiMatchs.length; t < len3; t++) + { + var twe = twemojiMatchs[t].replace(/:/g, "").replace("tw-", ""); + return "\"twemoji-""; + } + } + else + { + var src = (name === "+1") ? "plus1" : name; + src = (src === "black_large_square") ? "black_square" : src; + src = (src === "moon") ? "waxing_gibbous_moon" : src; + + return "\":""; + } + } + }); + } + + return text; + }; + + markedRenderer.atLink = function(text) { + + if (atLinkReg.test(text)) + { + if (settings.atLink) + { + text = text.replace(emailReg, function($1, $2, $3, $4) { + return $1.replace(/@/g, "_#_@_#_"); + }); + + text = text.replace(atLinkReg, function($1, $2) { + return "" + $1 + ""; + }).replace(/_#_@_#_/g, "@"); + } + + if (settings.emailLink) + { + text = text.replace(emailLinkReg, function($1, $2, $3, $4, $5) { + return (!$2 && $.inArray($5, "jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|")) < 0) ? ""+$1+"" : $1; + }); + } + + return text; + } + + return text; + }; + + markedRenderer.link = function (href, title, text) { + + if (this.options.sanitize) { + try { + var prot = decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase(); + } catch(e) { + return ""; + } + + if (prot.indexOf("javascript:") === 0) { + return ""; + } + } + + var out = "" + text.replace(/@/g, "@") + ""; + } + + if (title) { + out += " title=\"" + title + "\""; + } + + out += ">" + text + ""; + + return out; + }; + + markedRenderer.heading = function(text, level, raw) { + + var linkText = text; + var hasLinkReg = /\s*\]*)\>(.*)\<\/a\>\s*/; + var getLinkTextReg = /\s*\]+)\>([^\>]*)\<\/a\>\s*/g; + + if (hasLinkReg.test(text)) + { + var tempText = []; + text = text.split(/\]+)\>([^\>]*)\<\/a\>/); + + for (var i = 0, len = text.length; i < len; i++) + { + tempText.push(text[i].replace(/\s*href\=\"(.*)\"\s*/g, "")); + } + + text = tempText.join(" "); + } + + text = trim(text); + + var escapedText = text.toLowerCase().replace(/[^\w]+/g, "-"); + var toc = { + text : text, + level : level, + slug : escapedText + }; + + var isChinese = /^[\u4e00-\u9fa5]+$/.test(text); + var id = (isChinese) ? escape(text).replace(/\%/g, "") : text.toLowerCase().replace(/[^\w]+/g, "-"); + + markdownToC.push(toc); + + var headingHTML = ""; + + headingHTML += ""; + headingHTML += ""; + headingHTML += (hasLinkReg) ? this.atLink(this.emoji(linkText)) : this.atLink(this.emoji(text)); + headingHTML += ""; + + return headingHTML; + }; + + markedRenderer.pageBreak = function(text) { + if (pageBreakReg.test(text) && settings.pageBreak) + { + text = "
      "; + } + + return text; + }; + + markedRenderer.paragraph = function(text) { + var isTeXInline = /\$\$(.*)\$\$/g.test(text); + var isTeXLine = /^\$\$(.*)\$\$$/.test(text); + var isTeXAddClass = (isTeXLine) ? " class=\"" + editormd.classNames.tex + "\"" : ""; + var isToC = (settings.tocm) ? /^(\[TOC\]|\[TOCM\])$/.test(text) : /^\[TOC\]$/.test(text); + var isToCMenu = /^\[TOCM\]$/.test(text); + + if (!isTeXLine && isTeXInline) + { + text = text.replace(/(\$\$([^\$]*)\$\$)+/g, function($1, $2) { + return "" + $2.replace(/\$/g, "") + ""; + }); + } + else + { + text = (isTeXLine) ? text.replace(/\$/g, "") : text; + } + + var tocHTML = "
      " + text + "
      "; + + return (isToC) ? ( (isToCMenu) ? "
      " + tocHTML + "

      " : tocHTML ) + : ( (pageBreakReg.test(text)) ? this.pageBreak(text) : "" + this.atLink(this.emoji(text)) + "

      \n" ); + }; + + markedRenderer.code = function (code, lang, escaped) { + + if (lang === "seq" || lang === "sequence") + { + return "
      " + code + "
      "; + } + else if ( lang === "flow") + { + return "
      " + code + "
      "; + } + else if ( lang === "math" || lang === "latex" || lang === "katex") + { + return "

      " + code + "

      "; + } + else + { + + return marked.Renderer.prototype.code.apply(this, arguments); + } + }; + + markedRenderer.tablecell = function(content, flags) { + var type = (flags.header) ? "th" : "td"; + var tag = (flags.align) ? "<" + type +" style=\"text-align:" + flags.align + "\">" : "<" + type + ">"; + + return tag + this.atLink(this.emoji(content)) + "\n"; + }; + + markedRenderer.listitem = function(text) { + if (settings.taskList && /^\s*\[[x\s]\]\s*/.test(text)) + { + text = text.replace(/^\s*\[\s\]\s*/, " ") + .replace(/^\s*\[x\]\s*/, " "); + + return "
    • " + this.atLink(this.emoji(text)) + "
    • "; + } + else + { + return "
    • " + this.atLink(this.emoji(text)) + "
    • "; + } + }; + + return markedRenderer; + }; + + /** + * + * 生成TOC(Table of Contents) + * Creating ToC (Table of Contents) + * + * @param {Array} toc 从marked获取的TOC数组列表 + * @param {Element} container 插入TOC的容器元素 + * @param {Integer} startLevel Hx 起始层级 + * @returns {Object} tocContainer 返回ToC列表容器层的jQuery对象元素 + */ + + editormd.markdownToCRenderer = function(toc, container, tocDropdown, startLevel) { + + var html = ""; + var lastLevel = 0; + var classPrefix = this.classPrefix; + + startLevel = startLevel || 1; + + for (var i = 0, len = toc.length; i < len; i++) + { + var text = toc[i].text; + var level = toc[i].level; + + if (level < startLevel) { + continue; + } + + if (level > lastLevel) + { + html += ""; + } + else if (level < lastLevel) + { + html += (new Array(lastLevel - level + 2)).join(""); + } + else + { + html += ""; + } + + html += "
    • " + text + "
    • ",r+='
    • '+c+"
        ",a=h)}var d=t.find(".markdown-toc");if(d.length<1&&"false"===t.attr("previewContainer")){var u='
        ';u=i?'
        '+u+"
        ":u,t.html(u),d=t.find(".markdown-toc")}return i&&d.wrap('

        '),d.html('
          ').children(".markdown-toc-list").html(r.replace(/\r?\n?\\<\/ul\>/g,"")),d},r.tocDropdownMenu=function(t,i){i=i||"Table of Contents";var o=400,r=t.find("."+this.classPrefix+"toc-menu");return r.each(function(){var t=e(this),r=t.children(".markdown-toc"),a='',n=''+a+i+"",s=r.children("ul"),l=s.find("li");r.append(n),l.first().before("
        • "+i+" "+a+"

        • "),t.mouseover(function(){s.show(),l.each(function(){var t=e(this),i=t.children("ul");if(""===i.html()&&i.remove(),i.length>0&&""!==i.html()){var r=t.children("a").first();r.children(".fa").length<1&&r.append(e(a).css({float:"right",paddingTop:"4px"}))}t.mouseover(function(){i.css("z-index",o).show(),o+=1}).mouseleave(function(){i.hide()})})}).mouseleave(function(){s.hide()})}),r},r.filterHTMLTags=function(t,i){if("string"!=typeof t&&(t=new String(t)),"string"!=typeof i)return t;for(var o=i.split("|"),r=o[0].split(","),a=o[1],n=0,s=r.length;n]*)>([^>]*)","igm"),"")}if(void 0!==a){var c=/\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/gi;t="*"===a?t.replace(c,function(e,t,i,o,r){return"<"+t+">"+o+""}):"on*"===a?t.replace(c,function(t,i,o,r,a){var n=e("<"+i+">"+r+""),s=e(t)[0].attributes,l={};e.each(s,function(e,t){'"'!==t.nodeName&&(l[t.nodeName]=t.nodeValue)}),e.each(l,function(e){0===e.indexOf("on")&&delete l[e]}),n.attr(l);var c=void 0!==n[1]?e(n[1]).text():"";return n[0].outerHTML+c}):t.replace(c,function(t,i,o,r){var n=a.split(","),s=e(t);return s.html(r),e.each(n,function(e){s.attr(n[e],null)}),s[0].outerHTML})}return t},r.markdownToHTML=function(t,i){r.$marked=marked;var o=e("#"+t),a=o.settings=e.extend(!0,{gfm:!0,toc:!0,tocm:!1,tocStartLevel:1,tocTitle:"目录",tocDropdown:!1,tocContainer:"",markdown:"",markdownSourceCode:!1,htmlDecode:!1,autoLoadKaTeX:!0,pageBreak:!0,atLink:!0,emailLink:!0,tex:!1,taskList:!1,emoji:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0},i||{}),n=o.find("textarea");n.length<1&&(o.append(""),n=o.find("textarea"));var s=""===a.markdown?n.val():a.markdown,l=[],c={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,taskList:a.taskList,emoji:a.emoji,tex:a.tex,pageBreak:a.pageBreak,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},h={renderer:r.markedRenderer(l,c),gfm:a.gfm,tables:!0,breaks:!0,pedantic:!1,sanitize:!a.htmlDecode,smartLists:!0,smartypants:!0};s=new String(s);var d=marked(s,h);d=r.filterHTMLTags(d,a.htmlDecode),a.markdownSourceCode?n.text(s):n.remove(),o.addClass("markdown-body "+this.classPrefix+"html-preview").append(d);var u=""!==a.tocContainer?e(a.tocContainer):o;if(""!==a.tocContainer&&u.attr("previewContainer",!1),a.toc&&(o.tocContainer=this.markdownToCRenderer(l,u,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||o.find("."+this.classPrefix+"toc-menu").length>0)&&this.tocDropdownMenu(o,a.tocTitle),""!==a.tocContainer&&o.find(".editormd-toc-menu, .editormd-markdown-toc").remove()),a.previewCodeHighlight&&(o.find("pre").addClass("prettyprint linenums"),prettyPrint()),r.isIE8||(a.flowChart&&o.find(".flowchart").flowChart(),a.sequenceDiagram&&o.find(".sequence-diagram").sequenceDiagram({theme:"simple"})),a.tex){var f=function(){o.find("."+r.classNames.tex).each(function(){var t=e(this);katex.render(t.text(),t[0]),t.find(".katex").css("font-size","1.0em")})};!a.autoLoadKaTeX||r.$katex||r.kaTeXLoaded?f():this.loadKaTeX(function(){r.$katex=katex,r.kaTeXLoaded=!0,f()})}return o.getMarkdown=function(){return n.val()},o},r.themes=["default","dark"],r.previewThemes=["default","dark"],r.editorThemes=["default","3024-day","3024-night","ambiance","ambiance-mobile","base16-dark","base16-light","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","mbo","mdn-like","midnight","monokai","neat","neo","night","paraiso-dark","paraiso-light","pastel-on-dark","rubyblue","solarized","the-matrix","tomorrow-night-eighties","twilight","vibrant-ink","xq-dark","xq-light"],r.loadPlugins={},r.loadFiles={js:[],css:[],plugin:[]},r.loadPlugin=function(e,t,i){t=t||function(){},this.loadScript(e,function(){r.loadFiles.plugin.push(e),t()},i)},r.loadCSS=function(e,t,i){i=i||"head",t=t||function(){};var o=document.createElement("link");o.type="text/css",o.rel="stylesheet",o.onload=o.onreadystatechange=function(){r.loadFiles.css.push(e),t()},o.href=e+".css","head"===i?document.getElementsByTagName("head")[0].appendChild(o):document.body.appendChild(o)},r.isIE="Microsoft Internet Explorer"==navigator.appName,r.isIE8=r.isIE&&"8."==navigator.appVersion.match(/8./i),r.loadScript=function(e,t,i){i=i||"head",t=t||function(){};var o=null;(o=document.createElement("script")).id=e.replace(/[\./]+/g,"-"),o.type="text/javascript",o.src=e+".js",r.isIE8?o.onreadystatechange=function(){o.readyState&&("loaded"!==o.readyState&&"complete"!==o.readyState||(o.onreadystatechange=null,r.loadFiles.js.push(e),t()))}:o.onload=function(){r.loadFiles.js.push(e),t()},"head"===i?document.getElementsByTagName("head")[0].appendChild(o):document.body.appendChild(o)},r.katexURL={css:"/katex/katex.min",js:"/katex/katex.min"},r.kaTeXLoaded=!1,r.loadKaTeX=function(e){r.loadCSS(r.katexURL.css,function(){r.loadScript(r.katexURL.js,e||function(){})})},r.lockScreen=function(t){e("html,body").css("overflow",t?"hidden":"")},r.createDialog=function(t){t=e.extend(!0,{name:"",width:420,height:240,title:"",drag:!0,closed:!0,content:"",mask:!0,maskStyle:{backgroundColor:"#fff",opacity:.1},lockScreen:!0,footer:!0,buttons:!1},t);var i=this,o=this.editor,a=r.classPrefix,n=(new Date).getTime(),s=""===t.name?a+"dialog-"+n:t.name,l=r.mouseOrTouch,c='
          ';""!==t.title&&(c+='
          ",c+=''+t.title+"",c+="
          "),t.closed&&(c+=''),c+='
          '+t.content,(t.footer||"string"==typeof t.footer)&&(c+='"),c+="
          ",c+='
          ',c+='
          ',c+="
          ",o.append(c);var h=o.find("."+s);h.lockScreen=function(o){return t.lockScreen&&(e("html,body").css("overflow",o?"hidden":""),i.resize()),h},h.showMask=function(){return t.mask&&o.find("."+a+"mask").css(t.maskStyle).css("z-index",r.dialogZindex-1).show(),h},h.hideMask=function(){return t.mask&&o.find("."+a+"mask").hide(),h},h.loading=function(e){return h.find("."+a+"dialog-mask")[e?"show":"hide"](),h},h.lockScreen(!0).showMask(),h.show().css({zIndex:r.dialogZindex,border:r.isIE8?"1px solid #ddd":"",width:"number"==typeof t.width?t.width+"px":t.width,height:"number"==typeof t.height?t.height+"px":t.height});var d=function(){h.css({top:(e(window).height()-h.height())/2+"px",left:(e(window).width()-h.width())/2+"px"})};if(d(),e(window).resize(d),h.children("."+a+"dialog-close").bind(l("click","touchend"),function(){h.hide().lockScreen(!1).hideMask()}),"object"==typeof t.buttons){var u=h.footer=h.find("."+a+"dialog-footer");for(var f in t.buttons){var p=t.buttons[f],m=a+f+"-btn";u.append('"),p[1]=e.proxy(p[1],h),u.children("."+m).bind(l("click","touchend"),p[1])}}if(""!==t.title&&t.drag){var g,w,v=h.children("."+a+"dialog-header");t.mask||v.bind(l("click","touchend"),function(){r.dialogZindex+=2,h.css("z-index",r.dialogZindex)}),v.mousedown(function(e){e=e||window.event,g=e.clientX-parseInt(h[0].style.left),w=e.clientY-parseInt(h[0].style.top),document.onmousemove=x});var k=function(e){e.removeClass(a+"user-unselect").off("selectstart")},b=function(e){e.addClass(a+"user-unselect").on("selectstart",function(e){return!1})},x=function(t){t=t||window.event;var i,o,r=parseInt(h[0].style.left),a=parseInt(h[0].style.top);r>=0?r+h.width()<=e(window).width()?i=t.clientX-g:(i=e(window).width()-h.width(),document.onmousemove=null):(i=0,document.onmousemove=null),a>=0?o=t.clientY-w:(o=0,document.onmousemove=null),document.onselectstart=function(){return!1},b(e("body")),b(h),h[0].style.left=i+"px",h[0].style.top=o+"px"};document.onmouseup=function(){k(e("body")),k(h),document.onselectstart=null,document.onmousemove=null},v.touchDraggable=function(){var t=null;this.bind("touchstart",function(i){var o=i.originalEvent,r=e(this).parent().position();t={x:o.changedTouches[0].pageX-r.left,y:o.changedTouches[0].pageY-r.top}}).bind("touchmove",function(i){i.preventDefault();var o=i.originalEvent;e(this).parent().css({top:o.changedTouches[0].pageY-t.y,left:o.changedTouches[0].pageX-t.x})})},v.touchDraggable()}return r.dialogZindex+=2,e("body").removeAttr("style"),h},r.mouseOrTouch=function(e,t){t=t||"touchend";var i=e=e||"click";try{document.createEvent("TouchEvent"),i=t}catch(e){}return i},r.dateFormat=function(e){e=e||"";var t=function(e){return e<10?"0"+e:e},i=new Date,o=i.getFullYear(),r=o.toString().slice(2,4),a=t(i.getMonth()+1),n=t(i.getDate()),s=i.getDay(),l=t(i.getHours()),c=t(i.getMinutes()),h=t(i.getSeconds()),d=t(i.getMilliseconds()),u="",f=r+"-"+a+"-"+n,p=o+"-"+a+"-"+n,m=l+":"+c+":"+h;switch(e){case"UNIX Time":u=i.getTime();break;case"UTC":u=i.toUTCString();break;case"yy":u=r;break;case"year":case"yyyy":u=o;break;case"month":case"mm":u=a;break;case"cn-week-day":case"cn-wd":u="星期"+["日","一","二","三","四","五","六"][s];break;case"week-day":case"wd":u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][s];break;case"day":case"dd":u=n;break;case"hour":case"hh":u=l;break;case"min":case"ii":u=c;break;case"second":case"ss":u=h;break;case"ms":u=d;break;case"yy-mm-dd":u=f;break;case"yyyy-mm-dd":u=p;break;case"yyyy-mm-dd h:i:s ms":case"full + ms":u=p+" "+m+" "+d;break;case"full":case"yyyy-mm-dd h:i:s":default:u=p+" "+m}return u},r}}),window._whenPasterDoUpload=function(e,t,i){var o,r,a,n=e.clipboardData,s=0;if(n){if(!(o=n.items))return;for(r=o[0],a=n.types||[];sa',ucwords:'Aa'},toolbarIconsClass:{undo:"fa-undo",redo:"fa-repeat",bold:"fa-bold",del:"fa-strikethrough",italic:"fa-italic",quote:"fa-quote-left",uppercase:"fa-font",h1:r.classPrefix+"bold",h2:r.classPrefix+"bold",h3:r.classPrefix+"bold",h4:r.classPrefix+"bold",h5:r.classPrefix+"bold",h6:r.classPrefix+"bold","list-ul":"fa-list-ul","list-ol":"fa-list-ol",hr:"fa-minus",link:"fa-link","reference-link":"fa-anchor",image:"fa-picture-o",code:"fa-code","preformatted-text":"fa-file-code-o","code-block":"fa-file-code-o",table:"fa-table",datetime:"fa-clock-o",emoji:"fa-smile-o","html-entities":"fa-copyright",pagebreak:"fa-newspaper-o","goto-line":"fa-terminal",watch:"fa-eye-slash",unwatch:"fa-eye",preview:"fa-desktop",search:"fa-search",fullscreen:"fa-arrows-alt",clear:"fa-eraser",help:"fa-question-circle",info:"fa-info-circle"},toolbarIconTexts:{},lang:{name:"zh-cn",description:"开源在线Markdown编辑器
          Open source online Markdown editor.",tocTitle:"目录",toolbar:{undo:"撤销(Ctrl+Z)",redo:"重做(Ctrl+Y)",bold:"粗体",del:"删除线",italic:"斜体",quote:"引用",ucwords:"将每个单词首字母转成大写",uppercase:"将所选转换成大写",lowercase:"将所选转换成小写",h1:"标题1",h2:"标题2",h3:"标题3",h4:"标题4",h5:"标题5",h6:"标题6","list-ul":"无序列表","list-ol":"有序列表",hr:"横线",link:"链接","reference-link":"引用链接",image:"添加图片",code:"行内代码","preformatted-text":"预格式文本 / 代码块(缩进风格)","code-block":"代码块(多语言风格)",table:"添加表格",datetime:"日期时间",emoji:"Emoji表情","html-entities":"HTML实体字符",pagebreak:"插入分页符","goto-line":"跳转到行",watch:"关闭实时预览",unwatch:"开启实时预览",preview:"全窗口预览HTML(按 Shift + ESC还原)",fullscreen:"全屏(按ESC还原)",clear:"清空",search:"搜索",help:"使用帮助",info:"关于"+r.title},buttons:{enter:"确定",cancel:"取消",close:"关闭"},dialog:{link:{title:"添加链接",url:"链接地址",urlTitle:"链接标题",urlEmpty:"错误:请填写链接地址。"},referenceLink:{title:"添加引用链接",name:"引用名称",url:"链接地址",urlId:"链接ID",urlTitle:"链接标题",nameEmpty:"错误:引用链接的名称不能为空。",idEmpty:"错误:请填写引用链接的ID。",urlEmpty:"错误:请填写引用链接的URL地址。"},image:{title:"添加图片",url:"图片地址",link:"图片链接",alt:"图片描述",uploadButton:"本地上传",imageURLEmpty:"错误:图片地址不能为空。",uploadFileEmpty:"错误:上传的图片不能为空。",formatNotAllowed:"错误:只允许上传图片文件,允许上传的图片文件格式有:"},preformattedText:{title:"添加预格式文本或代码块",emptyAlert:"错误:请填写预格式文本或代码的内容。"},codeBlock:{title:"添加代码块",selectLabel:"代码语言:",selectDefaultText:"请选择代码语言",otherLanguage:"其他语言",unselectedLanguageAlert:"错误:请选择代码所属的语言类型。",codeEmptyAlert:"错误:请填写代码内容。"},htmlEntities:{title:"HTML 实体字符"},help:{title:"使用帮助"}}}},r.classNames={tex:r.classPrefix+"tex"},r.dialogZindex=99999,r.$katex=null,r.$marked=null,r.$CodeMirror=null,r.$prettyPrint=null,r.prototype=r.fn={state:{watching:!1,loaded:!1,preview:!1,fullscreen:!1},init:function(t,i){i=i||{},"object"==typeof t&&(i=t);var a=this.classPrefix=r.classPrefix,n=o=e.extend(!0,r.defaults,i);this.settings=n,t="object"==typeof t?n.id:t;var s=this.editor=e("#"+t);this.id=t,this.lang=n.lang;var l=this.classNames={textarea:{html:a+"html-textarea",markdown:a+"markdown-textarea"}};n.pluginPath=""===n.pluginPath?n.path+"../plugins/":n.pluginPath,this.state.watching=!!n.watch,s.hasClass("editormd")||s.addClass("editormd"),s.css({width:"number"==typeof n.width?n.width+"px":n.width,height:"number"==typeof n.height?n.height+"px":n.height}),n.autoHeight&&s.css("height","auto");var c=this.markdownTextarea=s.children("textarea");c.length<1&&(s.append(""),c=this.markdownTextarea=s.children("textarea")),c.addClass(l.textarea.markdown).attr("placeholder",n.placeholder),void 0!==c.attr("name")&&""!==c.attr("name")||c.attr("name",""!==n.name?n.name:t+"-markdown-doc");var h=[n.readOnly?"":'',n.saveHTMLToTextarea?'':"",'
          ','
          ','
          '].join("\n");return s.append(h).addClass(a+"vertical"),""!==n.theme&&s.addClass(a+"theme-"+n.theme),this.mask=s.children("."+a+"mask"),this.containerMask=s.children("."+a+"container-mask"),""!==n.markdown&&c.val(n.markdown),""!==n.appendMarkdown&&c.val(c.val()+n.appendMarkdown),this.htmlTextarea=s.children("."+l.textarea.html),this.preview=s.children("."+a+"preview"),this.previewContainer=this.preview.children("."+a+"preview-container"),""!==n.previewTheme&&this.preview.addClass(a+"preview-theme-"+n.previewTheme),"function"==typeof define&&define.amd&&("undefined"!=typeof katex&&(r.$katex=katex),n.searchReplace&&!n.readOnly&&(r.loadCSS(n.path+"codemirror/addon/dialog/dialog"),r.loadCSS(n.path+"codemirror/addon/search/matchesonscrollbar"))),"function"==typeof define&&define.amd||!n.autoLoadModules?("undefined"!=typeof CodeMirror&&(r.$CodeMirror=CodeMirror),"undefined"!=typeof marked&&(r.$marked=marked),this.setCodeMirror().setToolbar().loadedDisplay()):this.loadQueues(),this},loadQueues:function(){var e=this,t=o,i=t.path,a=function(){r.isIE8?e.loadedDisplay():t.flowChart||t.sequenceDiagram?r.loadScript(i+"raphael.min",function(){r.loadScript(i+"underscore.min",function(){!t.flowChart&&t.sequenceDiagram?r.loadScript(i+"sequence-diagram.min",function(){e.loadedDisplay()}):t.flowChart&&!t.sequenceDiagram?r.loadScript(i+"flowchart.min",function(){r.loadScript(i+"jquery.flowchart.min",function(){e.loadedDisplay()})}):t.flowChart&&t.sequenceDiagram&&r.loadScript(i+"flowchart.min",function(){r.loadScript(i+"jquery.flowchart.min",function(){r.loadScript(i+"sequence-diagram.min",function(){e.loadedDisplay()})})})})}):e.loadedDisplay()};return t.searchReplace&&!t.readOnly&&(r.loadCSS(i+"codemirror/addon/dialog/dialog"),r.loadCSS(i+"codemirror/addon/search/matchesonscrollbar")),t.codeFold&&r.loadCSS(i+"codemirror/addon/fold/foldgutter"),r.$CodeMirror=CodeMirror,r.loadScript(i+"codemirror/modes.min",function(){r.loadScript(i+"codemirror/addons.min",function(){if(e.setCodeMirror(),"gfm"!==t.mode&&"markdown"!==t.mode)return e.loadedDisplay(),!1;e.setToolbar(),r.loadScript(i+"marked.min",function(){r.$marked=marked,t.previewCodeHighlight?r.loadScript(i+"prettify.min",function(){a()}):a()})})}),this},setTheme:function(e){var t=this.editor,i=o.theme,r=this.classPrefix+"theme-";return t.removeClass(r+i).addClass(r+e),o.theme=e,this},setEditorTheme:function(e){var t=o;return t.editorTheme=e,"default"!==e&&r.loadCSS(t.path+"codemirror/theme/"+t.editorTheme),this.cm.setOption("theme",e),this},setCodeMirrorTheme:function(e){return this.setEditorTheme(e),this},setPreviewTheme:function(e){var t=this.preview,i=o.previewTheme,r=this.classPrefix+"preview-theme-";return t.removeClass(r+i).addClass(r+e),o.previewTheme=e,this},setCodeMirror:function(){var e=o,t=this.editor;"default"!==e.editorTheme&&r.loadCSS(e.path+"codemirror/theme/"+e.editorTheme);var i={mode:e.mode,theme:e.editorTheme,tabSize:e.tabSize,dragDrop:!1,autofocus:e.autoFocus,autoCloseTags:e.autoCloseTags,readOnly:!!e.readOnly&&"nocursor",indentUnit:e.indentUnit,lineNumbers:e.lineNumbers,lineWrapping:e.lineWrapping,extraKeys:{"Ctrl-Q":function(e){e.foldCode(e.getCursor())}},foldGutter:e.codeFold,gutters:["CodeMirror-linenumbers","CodeMirror-foldgutter"],matchBrackets:e.matchBrackets,indentWithTabs:e.indentWithTabs,styleActiveLine:e.styleActiveLine,styleSelectedText:e.styleSelectedText,autoCloseBrackets:e.autoCloseBrackets,showTrailingSpace:e.showTrailingSpace,highlightSelectionMatches:!!e.matchWordHighlight&&{showToken:"onselected"!==e.matchWordHighlight&&/\w/}};return this.codeEditor=this.cm=r.$CodeMirror.fromTextArea(this.markdownTextarea[0],i),this.codeMirror=this.cmElement=t.children(".CodeMirror"),""!==e.value&&this.cm.setValue(e.value),this.codeMirror.css({fontSize:e.fontSize,width:e.watch?"50%":"100%"}),e.autoHeight&&(this.codeMirror.css("height","auto"),this.cm.setOption("viewportMargin",1/0)),e.lineNumbers||this.codeMirror.find(".CodeMirror-gutters").css("border-right","none"),this},getCodeMirrorOption:function(e){return this.cm.getOption(e)},setCodeMirrorOption:function(e,t){return this.cm.setOption(e,t),this},addKeyMap:function(e,t){return this.cm.addKeyMap(e,t),this},removeKeyMap:function(e){return this.cm.removeKeyMap(e),this},gotoLine:function(t){var i=o;if(!i.gotoLine)return this;var r=this.cm,a=(this.editor,r.lineCount()),n=this.preview;if("string"==typeof t&&("last"===t&&(t=a),"first"===t&&(t=1)),"number"!=typeof t)return alert("Error: The line number must be an integer."),this;if((t=parseInt(t)-1)>a)return alert("Error: The line number range 1-"+a),this;r.setCursor({line:t,ch:0});var s=r.getScrollInfo().clientHeight,l=r.charCoords({line:t,ch:0},"local");if(r.scrollTo(null,(l.top+l.bottom-s)/2),i.watch){var c=this.codeMirror.find(".CodeMirror-scroll")[0],h=e(c).height(),d=c.scrollTop,u=d/c.scrollHeight;0===d?n.scrollTop(0):d+h>=c.scrollHeight-16?n.scrollTop(n[0].scrollHeight):n.scrollTop(n[0].scrollHeight*u)}return r.focus(),this},extend:function(){return void 0!==arguments[1]&&("function"==typeof arguments[1]&&(arguments[1]=e.proxy(arguments[1],this)),this[arguments[0]]=arguments[1]),"object"==typeof arguments[0]&&void 0===arguments[0].length&&e.extend(!0,this,arguments[0]),this},set:function(t,i){return void 0!==i&&"function"==typeof i&&(i=e.proxy(i,this)),this[t]=i,this},config:function(t,i){var r=o;return"object"==typeof t&&(r=e.extend(!0,r,t)),"string"==typeof t&&(r[t]=i),o=r,this.recreate(),this},on:function(t,i){var r=o;return void 0!==r["on"+t]&&(r["on"+t]=e.proxy(i,this)),this},off:function(e){var t=o;return void 0!==t["on"+e]&&(t["on"+e]=function(){}),this},showToolbar:function(t){var i=o;return i.readOnly?this:(i.toolbar&&(this.toolbar.length<1||""===this.toolbar.find("."+this.classPrefix+"menu").html())&&this.setToolbar(),i.toolbar=!0,this.toolbar.show(),this.resize(),e.proxy(t||function(){},this)(),this)},hideToolbar:function(t){return o.toolbar=!1,this.toolbar.hide(),this.resize(),e.proxy(t||function(){},this)(),this},setToolbarAutoFixed:function(t){var i=this.state,r=this.editor,a=this.toolbar,n=o;void 0!==t&&(n.toolbarAutoFixed=t);return!i.fullscreen&&!i.preview&&n.toolbar&&n.toolbarAutoFixed&&e(window).bind("scroll",function(){var t=e(window),i=t.scrollTop();if(!n.toolbarAutoFixed)return!1;i-r.offset().top>10&&i
            ';t.append(n),a=this.toolbar=t.children("."+i+"toolbar")}if(!e.toolbar)return a.hide(),this;a.show();for(var s="function"==typeof e.toolbarIcons?e.toolbarIcons(this):"string"==typeof e.toolbarIcons?r.toolbarModes[e.toolbarIcons]:e.toolbarIcons,l=a.find("."+this.classPrefix+"menu"),c="",h=!1,d=0,u=s.length;d|';else{var p=/h(\d)/.test(f),m=f;"watch"!==f||e.watch||(m="unwatch");var g=e.lang.toolbar[m],w=e.toolbarIconTexts[m],v=e.toolbarIconsClass[m];g=void 0===g?"":g,w=void 0===w?"":w,v=void 0===v?"":v;var k=h?'
          • ':"
          • ";void 0!==e.toolbarCustomIcons[f]&&"function"!=typeof e.toolbarCustomIcons[f]?k+=e.toolbarCustomIcons[f]:(k+='',k+=''+(p?f.toUpperCase():""===v?w:"")+"",k+=""),k+="
          • ",c=h?k+c:c+k}}return l.html(c),l.find('[title="Lowercase"]').attr("title",e.lang.toolbar.lowercase),l.find('[title="ucwords"]').attr("title",e.lang.toolbar.ucwords),this.setToolbarHandler(),this.setToolbarAutoFixed(),this},dialogLockScreen:function(){return e.proxy(r.dialogLockScreen,this)(),this},dialogShowMask:function(t){return e.proxy(r.dialogShowMask,this)(t),this},getToolbarHandles:function(e){var t=this.toolbarHandlers=r.toolbarHandlers;return e&&void 0!==toolbarIconHandlers[e]?t[e]:t},setToolbarHandler:function(){var t=this,i=o;if(!i.toolbar||i.readOnly)return this;var a=this.toolbar,n=this.cm,s=this.classPrefix,l=this.toolbarIcons=a.find("."+s+"menu > li > a"),c=this.getToolbarHandles();return l.bind(r.mouseOrTouch("click","touchend"),function(o){var r=e(this).children(".fa"),a=r.attr("name"),s=n.getCursor(),l=n.getSelection();if(""!==a)return t.activeIcon=r,void 0!==c[a]?e.proxy(c[a],t)(n):void 0!==i.toolbarHandlers[a]&&e.proxy(i.toolbarHandlers[a],t)(n,r,s,l),"link"!==a&&"reference-link"!==a&&"image"!==a&&"code-block"!==a&&"preformatted-text"!==a&&"watch"!==a&&"preview"!==a&&"search"!==a&&"fullscreen"!==a&&"info"!==a&&n.focus(),!1}),this},createDialog:function(t){return e.proxy(r.createDialog,this)(t)},createInfoDialog:function(){var e=this,t=this.editor,i=this.classPrefix,o=['
            ','
            ','

            '+r.title+"v"+r.version+"

            ","

            "+this.lang.description+"

            ",'

            '+r.homePage+'

            ','

            Copyright © 2015 Pandao, The MIT License.

            ',"
            ",'',"
            "].join("\n");t.append(o);var a=this.infoDialog=t.children("."+i+"dialog-info");return a.find("."+i+"dialog-close").bind(r.mouseOrTouch("click","touchend"),function(){e.hideInfoDialog()}),a.css("border",r.isIE8?"1px solid #ddd":"").css("z-index",r.dialogZindex).show(),this.infoDialogPosition(),this},infoDialogPosition:function(){var t=this.infoDialog,i=function(){t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"})};return i(),e(window).resize(i),this},showInfoDialog:function(){e("html,body").css("overflow-x","hidden");var t=this.editor,i=o,a=this.infoDialog=t.children("."+this.classPrefix+"dialog-info");return a.length<1&&this.createInfoDialog(),this.lockScreen(!0),this.mask.css({opacity:i.dialogMaskOpacity,backgroundColor:i.dialogMaskBgColor}).show(),a.css("z-index",r.dialogZindex).show(),this.infoDialogPosition(),this},hideInfoDialog:function(){return e("html,body").css("overflow-x",""),this.infoDialog.hide(),this.mask.hide(),this.lockScreen(!1),this},lockScreen:function(e){return r.lockScreen(e),this.resize(),this},recreate:function(){var e=this.editor,t=o;return this.codeMirror.remove(),this.setCodeMirror(),t.readOnly||(e.find(".editormd-dialog").length>0&&e.find(".editormd-dialog").remove(),t.toolbar&&(this.getToolbarHandles(),this.setToolbar())),this.loadedDisplay(!0),this},previewCodeHighlight:function(){var e=o,t=this.previewContainer;return e.previewCodeHighlight&&(t.find("pre").addClass("prettyprint linenums"),"undefined"!=typeof prettyPrint&&prettyPrint()),this},katexRender:function(){return null===t?this:(this.previewContainer.find("."+r.classNames.tex).each(function(){var t=e(this);r.$katex.render(t.text(),t[0]),t.find(".katex").css("font-size","1.0em")}),this)},flowChartAndSequenceDiagramRender:function(){var t=o,a=this.previewContainer;if(r.isIE8)return this;if(t.flowChart){if(null===i)return this;a.find(".flowchart").flowChart()}t.sequenceDiagram&&a.find(".sequence-diagram").sequenceDiagram({theme:"simple"});var n=this.preview,s=this.codeMirror.find(".CodeMirror-scroll"),l=s.height(),c=s.scrollTop(),h=c/s[0].scrollHeight,d=0;n.find(".markdown-toc-list").each(function(){d+=e(this).height()});var u=n.find(".editormd-toc-menu").height();return u=u||0,0===c?n.scrollTop(0):c+l>=s[0].scrollHeight-16?n.scrollTop(n[0].scrollHeight):n.scrollTop((n[0].scrollHeight+d+u)*h),this},registerKeyMaps:function(t){var i=this,a=this.cm,n=o,s=r.toolbarHandlers,l=n.disabledKeyMaps;if(t=t||null){for(var c in t)if(e.inArray(c,l)<0){t[c],a.addKeyMap(t)}}else{for(var h in r.keyMaps){var d=r.keyMaps[h],u="string"==typeof d?e.proxy(s[d],i):e.proxy(d,i);if(e.inArray(h,["F9","F10","F11"])<0&&e.inArray(h,l)<0){var f={};f[h]=u,a.addKeyMap(f)}}e(window).keydown(function(t){if(e.inArray({120:"F9",121:"F10",122:"F11"}[t.keyCode],l)<0)switch(t.keyCode){case 120:return e.proxy(s.watch,i)(),!1;case 121:return e.proxy(s.preview,i)(),!1;case 122:return e.proxy(s.fullscreen,i)(),!1}})}return this},bindScrollEvent:function(){var t=this,i=this.preview,a=o,n=this.codeMirror,s=r.mouseOrTouch;if(!a.syncScrolling)return this;var l=function(){n.find(".CodeMirror-scroll").bind(s("scroll","touchmove"),function(o){var r=e(this).height(),n=e(this).scrollTop(),s=n/e(this)[0].scrollHeight,l=0;i.find(".markdown-toc-list").each(function(){l+=e(this).height()});var c=i.find(".editormd-toc-menu").height();c=c||0,0===n?i.scrollTop(0):n+r>=e(this)[0].scrollHeight-16?i.scrollTop(i[0].scrollHeight):i.scrollTop((i[0].scrollHeight+l+c)*s),e.proxy(a.onscroll,t)(o)})},c=function(){n.find(".CodeMirror-scroll").unbind(s("scroll","touchmove"))},h=function(){i.bind(s("scroll","touchmove"),function(i){var o=e(this).height(),r=e(this).scrollTop(),s=r/e(this)[0].scrollHeight,l=n.find(".CodeMirror-scroll");0===r?l.scrollTop(0):r+o>=e(this)[0].scrollHeight?l.scrollTop(l[0].scrollHeight):l.scrollTop(l[0].scrollHeight*s),e.proxy(a.onpreviewscroll,t)(i)})},d=function(){i.unbind(s("scroll","touchmove"))};return n.bind({mouseover:l,mouseout:c,touchstart:l,touchend:c}),"single"===a.syncScrolling?this:(i.bind({mouseover:h,mouseout:d,touchstart:h,touchend:d}),this)},bindChangeEvent:function(){var e=this,i=this.cm,r=o;return r.syncScrolling?(i.on("change",function(i,o){r.watch&&e.previewContainer.css("padding",r.autoHeight?"20px 20px 50px 40px":"20px"),t=setTimeout(function(){clearTimeout(t),e.save(),t=null},r.delay)}),this):this},loadedDisplay:function(t){t=t||!1;var i=this,r=this.editor,a=this.preview,n=o;return this.containerMask.hide(),this.save(),n.watch&&a.show(),r.data("oldWidth",r.width()).data("oldHeight",r.height()),this.resize(),this.registerKeyMaps(),e(window).resize(function(){i.resize()}),this.bindScrollEvent().bindChangeEvent(),t||(n.imageUploadURL&&initEditormdPasteUpload(this,n.imageUploadURL),e.proxy(n.onload,this)()),this.state.loaded=!0,this},width:function(e){return this.editor.css("width","number"==typeof e?e+"px":e),this.resize(),this},height:function(e){return this.editor.css("height","number"==typeof e?e+"px":e),this.resize(),this},resize:function(t,i){t=t||null,i=i||null;var r=this.state,a=this.editor,n=this.preview,s=this.toolbar,l=o,c=this.codeMirror;if(t&&a.css("width","number"==typeof t?t+"px":t),!l.autoHeight||r.fullscreen||r.preview?(i&&a.css("height","number"==typeof i?i+"px":i),r.fullscreen&&a.height(e(window).height()),l.toolbar&&!l.readOnly?c.css("margin-top",s.height()+1).height(a.height()-s.height()):c.css("margin-top",0).height(a.height())):(a.css("height","auto"),c.css("height","auto")),l.watch)if(c.width(a.width()/2),n.width(r.preview?a.width():a.width()/2),this.previewContainer.css("padding",l.autoHeight?"20px 20px 50px 40px":"20px"),l.toolbar&&!l.readOnly?n.css("top",s.height()+1):n.css("top",0),!l.autoHeight||r.fullscreen||r.preview){var h=l.toolbar&&!l.readOnly?a.height()-s.height():a.height();n.height(h)}else n.height("");else c.width(a.width()),n.hide();return r.loaded&&e.proxy(l.onresize,this)(),this},save:function(){if(null===t)return this;var a=this,n=this.state,s=o,l=this.cm,c=l.getValue(),h=this.previewContainer;if("gfm"!==s.mode&&"markdown"!==s.mode)return this.markdownTextarea.val(c),this;var d=r.$marked,u=this.markdownToC=[],f=this.markedRendererOptions={toc:s.toc,tocm:s.tocm,tocStartLevel:s.tocStartLevel,pageBreak:s.pageBreak,taskList:s.taskList,emoji:s.emoji,tex:s.tex,atLink:s.atLink,emailLink:s.emailLink,flowChart:s.flowChart,sequenceDiagram:s.sequenceDiagram,previewCodeHighlight:s.previewCodeHighlight},p=this.markedOptions={renderer:r.markedRenderer(u,f),gfm:!0,tables:!0,breaks:!0,pedantic:!1,sanitize:!s.htmlDecode,smartLists:!0,smartypants:!0};d.setOptions(p);var m=r.$marked(c,p);if(m=r.filterHTMLTags(m,s.htmlDecode),this.markdownTextarea.text(c),l.save(),s.saveHTMLToTextarea&&this.htmlTextarea.text(m),s.watch||!s.watch&&n.preview){if(h.html(m),this.previewCodeHighlight(),s.toc){var g=""===s.tocContainer?h:e(s.tocContainer),w=g.find("."+this.classPrefix+"toc-menu");g.attr("previewContainer",""===s.tocContainer?"true":"false"),""!==s.tocContainer&&w.length>0&&w.remove(),r.markdownToCRenderer(u,g,s.tocDropdown,s.tocStartLevel),(s.tocDropdown||g.find("."+this.classPrefix+"toc-menu").length>0)&&r.tocDropdownMenu(g,""!==s.tocTitle?s.tocTitle:this.lang.tocTitle),""!==s.tocContainer&&h.find(".markdown-toc").css("border","none")}s.tex&&(!r.kaTeXLoaded&&s.autoLoadModules?r.loadKaTeX(function(){r.$katex=katex,r.kaTeXLoaded=!0,a.katexRender()}):(r.$katex=katex,this.katexRender())),(s.flowChart||s.sequenceDiagram)&&(i=setTimeout(function(){clearTimeout(i),a.flowChartAndSequenceDiagramRender(),i=null},10)),n.loaded&&e.proxy(s.onchange,this)()}return this},focus:function(){return this.cm.focus(),this},setCursor:function(e){return this.cm.setCursor(e),this},getCursor:function(){return this.cm.getCursor()},setSelection:function(e,t){return this.cm.setSelection(e,t),this},getSelection:function(){return this.cm.getSelection()},setSelections:function(e){return this.cm.setSelections(e),this},getSelections:function(){return this.cm.getSelections()},replaceSelection:function(e){return this.cm.replaceSelection(e),this},insertValue:function(e){return this.replaceSelection(e),this},appendMarkdown:function(e){var t=this.cm;return t.setValue(t.getValue()+e),this},setMarkdown:function(e){return this.cm.setValue(e||o.markdown),this},getMarkdown:function(){return this.cm.getValue()},getValue:function(){return this.cm.getValue()},setValue:function(e){return this.cm.setValue(e),this},clear:function(){return this.cm.setValue(""),this},getHTML:function(){return o.saveHTMLToTextarea?this.htmlTextarea.val():(alert("Error: settings.saveHTMLToTextarea == false"),!1)},getTextareaSavedHTML:function(){return this.getHTML()},getPreviewedHTML:function(){return o.watch?this.previewContainer.html():(alert("Error: settings.watch == false"),!1)},watch:function(i){var r=o;if(e.inArray(r.mode,["gfm","markdown"])<0)return this;if(this.state.watching=r.watch=!0,this.preview.show(),this.toolbar){var a=r.toolbarIconsClass.watch,n=r.toolbarIconsClass.unwatch,s=this.toolbar.find(".fa[name=watch]");s.parent().attr("title",r.lang.toolbar.watch),s.removeClass(n).addClass(a)}return this.codeMirror.css("border-right","1px solid #ddd").width(this.editor.width()/2),t=0,this.save().resize(),r.onwatch||(r.onwatch=i||function(){}),e.proxy(r.onwatch,this)(),this},unwatch:function(t){var i=o;if(this.state.watching=i.watch=!1,this.preview.hide(),this.toolbar){var r=i.toolbarIconsClass.watch,a=i.toolbarIconsClass.unwatch,n=this.toolbar.find(".fa[name=watch]");n.parent().attr("title",i.lang.toolbar.unwatch),n.removeClass(r).addClass(a)}return this.codeMirror.css("border-right","none").width(this.editor.width()),this.resize(),i.onunwatch||(i.onunwatch=t||function(){}),e.proxy(i.onunwatch,this)(),this},show:function(t){t=t||function(){};var i=this;return this.editor.show(0,function(){e.proxy(t,i)()}),this},hide:function(t){t=t||function(){};var i=this;return this.editor.hide(0,function(){e.proxy(t,i)()}),this},previewing:function(){var t=this,i=this.editor,a=this.preview,n=this.toolbar,s=o,l=this.codeMirror,c=this.previewContainer;if(e.inArray(s.mode,["gfm","markdown"])<0)return this;s.toolbar&&n&&(n.toggle(),n.find(".fa[name=preview]").toggleClass("active")),l.toggle();var h=function(e){e.shiftKey&&27===e.keyCode&&t.previewed()};"none"===l.css("display")?(this.state.preview=!0,this.state.fullscreen&&a.css("background","#fff"),i.find("."+this.classPrefix+"preview-close-btn").show().bind(r.mouseOrTouch("click","touchend"),function(){t.previewed()}),s.watch?c.css("padding",""):this.save(),c.addClass(this.classPrefix+"preview-active"),a.show().css({position:"",top:0,width:i.width(),height:s.autoHeight&&!this.state.fullscreen?"auto":i.height()}),this.state.loaded&&e.proxy(s.onpreviewing,this)(),e(window).bind("keyup",h)):(e(window).unbind("keyup",h),this.previewed())},previewed:function(){var t=this.editor,i=this.preview,a=this.toolbar,n=o,s=this.previewContainer,l=t.find("."+this.classPrefix+"preview-close-btn");return this.state.preview=!1,this.codeMirror.show(),n.toolbar&&a.show(),i[n.watch?"show":"hide"](),l.hide().unbind(r.mouseOrTouch("click","touchend")),s.removeClass(this.classPrefix+"preview-active"),n.watch&&s.css("padding","20px"),i.css({background:null,position:"absolute",width:t.width()/2,height:n.autoHeight&&!this.state.fullscreen?"auto":t.height()-a.height(),top:n.toolbar?a.height():0}),this.state.loaded&&e.proxy(n.onpreviewed,this)(),this},fullscreen:function(){var t=this,i=this.state,r=this.editor,a=(this.preview,this.toolbar),n=o,s=this.classPrefix+"fullscreen";a&&a.find(".fa[name=fullscreen]").parent().toggleClass("active");var l=function(e){e.shiftKey||27!==e.keyCode||i.fullscreen&&t.fullscreenExit()};return r.hasClass(s)?(e(window).unbind("keyup",l),this.fullscreenExit()):(i.fullscreen=!0,e("html,body").css("overflow","hidden"),r.css({width:e(window).width(),height:e(window).height()}).addClass(s),this.resize(),e.proxy(n.onfullscreen,this)(),e(window).bind("keyup",l)),this},fullscreenExit:function(){var t=this.editor,i=o,r=this.toolbar,a=this.classPrefix+"fullscreen";return this.state.fullscreen=!1,r&&r.find(".fa[name=fullscreen]").parent().removeClass("active"),e("html,body").css("overflow",""),t.css({width:t.data("oldWidth"),height:t.data("oldHeight")}).removeClass(a),this.resize(),e.proxy(i.onfullscreenExit,this)(),this},executePlugin:function(t,i){var a=this,n=this.cm;return i=o.pluginPath+i,"function"==typeof define?void 0===this[t]?(alert("Error: "+t+" plugin is not found, you are not load this plugin."),this):(this[t](n),this):(e.inArray(i,r.loadFiles.plugin)<0?r.loadPlugin(i,function(){r.loadPlugins[t]=a[t],a[t](n)}):e.proxy(r.loadPlugins[t],this)(n),this)},search:function(e){var t=o;return t.searchReplace?(t.readOnly||this.cm.execCommand(e||"find"),this):(alert("Error: settings.searchReplace == false"),this)},searchReplace:function(){return this.search("replace"),this},searchReplaceAll:function(){return this.search("replaceAll"),this}},r.fn.init.prototype=r.fn,r.dialogLockScreen=function(){(o||{dialogLockScreen:!0}).dialogLockScreen&&(e("html,body").css("overflow","hidden"),this.resize())},r.dialogShowMask=function(t){var i=this.editor,r=o||{dialogShowMask:!0};t.css({top:(e(window).height()-t.height())/2+"px",left:(e(window).width()-t.width())/2+"px"}),r.dialogShowMask&&i.children("."+this.classPrefix+"mask").css("z-index",parseInt(t.css("z-index"))-1).show()},r.toolbarHandlers={undo:function(){this.cm.undo()},redo:function(){this.cm.redo()},bold:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("**"+i+"**"),""===i&&e.setCursor(t.line,t.ch+2)},del:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("~~"+i+"~~"),""===i&&e.setCursor(t.line,t.ch+2)},italic:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();e.replaceSelection("*"+i+"*"),""===i&&e.setCursor(t.line,t.ch+1)},quote:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("> "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("> "+i)},ucfirst:function(){var e=this.cm,t=e.getSelection(),i=e.listSelections();e.replaceSelection(r.firstUpperCase(t)),e.setSelections(i)},ucwords:function(){var e=this.cm,t=e.getSelection(),i=e.listSelections();e.replaceSelection(r.wordsFirstUpperCase(t)),e.setSelections(i)},uppercase:function(){var e=this.cm,t=e.getSelection(),i=e.listSelections();e.replaceSelection(t.toUpperCase()),e.setSelections(i)},lowercase:function(){var e=this.cm,t=(e.getCursor(),e.getSelection()),i=e.listSelections();e.replaceSelection(t.toLowerCase()),e.setSelections(i)},h1:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("# "+i),e.setCursor(t.line,t.ch+2)):e.replaceSelection("# "+i)},h2:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("## "+i),e.setCursor(t.line,t.ch+3)):e.replaceSelection("## "+i)},h3:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("### "+i),e.setCursor(t.line,t.ch+4)):e.replaceSelection("### "+i)},h4:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("#### "+i),e.setCursor(t.line,t.ch+5)):e.replaceSelection("#### "+i)},h5:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("##### "+i),e.setCursor(t.line,t.ch+6)):e.replaceSelection("##### "+i)},h6:function(){var e=this.cm,t=e.getCursor(),i=e.getSelection();0!==t.ch?(e.setCursor(t.line,0),e.replaceSelection("###### "+i),e.setCursor(t.line,t.ch+7)):e.replaceSelection("###### "+i)},"list-ul":function(){var e=this.cm,t=(e.getCursor(),e.getSelection());if(""===t)e.replaceSelection("- "+t);else{for(var i=t.split("\n"),o=0,r=i.length;o'}else{var l=e.match(m),c=e.match(f);if(l)for(var h=0,d=l.length;h'}else{if(!c){var g="+1"===o?"plus1":o;return g="moon"===(g="black_large_square"===g?"black_square":g)?"waxing_gibbous_moon":g,':'+o+':'}for(var w=0,v=c.length;w'}}}});return e},s.atLink=function(t){return c.test(t)?(o.atLink&&(t=(t=t.replace(d,function(e,t,i,o){return e.replace(/@/g,"_#_@_#_")})).replace(c,function(e,t){return''+e+""}).replace(/_#_@_#_/g,"@")),o.emailLink&&(t=t.replace(u,function(t,i,o,r,a){return!i&&e.inArray(a,"jpg|jpeg|png|gif|webp|ico|icon|pdf".split("|"))<0?''+t+"":t})),t):t},s.link=function(e,t,i){if(this.options.sanitize){try{var o=decodeURIComponent(unescape(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(0===o.indexOf("javascript:"))return""}var r=''+i.replace(/@/g,"@")+""):(t&&(r+=' title="'+t+'"'),r+=">"+i+"")},s.heading=function(e,i,o){var r=e,n=/\s*\]*)\>(.*)\<\/a\>\s*/;if(n.test(e)){for(var s=[],l=0,c=(e=e.split(/\]+)\>([^\>]*)\<\/a\>/)).length;l';return u+='',u+='',u+=n?this.atLink(this.emoji(r)):this.atLink(this.emoji(e)),u+=""},s.pageBreak=function(e){return g.test(e)&&o.pageBreak&&(e='
            '),e},s.em=function(e, capInput){return e&&-1!=e.indexOf("$$") || (capInput && capInput.indexOf('$$') != -1) ?"_"+e+"_":""+e+""},s.paragraph=function(e){var t=/\$\$(.*)\$\$/g.test(e),i=/^\$\$(.*)\$\$$/.test(e),a=i?' class="'+r.classNames.tex+'"':"",n=o.tocm?/^(\[TOC\]|\[TOCM\])$/.test(e):/^\[TOC\]$/.test(e),s=/^\[TOCM\]$/.test(e),l='
            '+(e=!i&&t?e.replace(/(\$\$([^\$]*)\$\$)+/g,function(e,t){return''+t.replace(/\$/g,"")+""}):i?e.replace(/\$/g,""):e)+"
            ";return n?s?'
            '+l+"

            ":l:g.test(e)?this.pageBreak(e):""+this.atLink(this.emoji(e))+"

            \n"},s.code=function(e,t,i){return"seq"===t||"sequence"===t?'
            '+e+"
            ":"flow"===t?'
            '+e+"
            ":"math"===t||"latex"===t||"katex"===t?'

            '+e+"

            ":n.Renderer.prototype.code.apply(this,arguments)},s.tablecell=function(e,t){var i=t.header?"th":"td";return(t.align?"<"+i+' style="text-align:'+t.align+'">':"<"+i+">")+this.atLink(this.emoji(e))+"\n"},s.listitem=function(e){return o.taskList&&/^\s*\[[x\s]\]\s*/.test(e)?(e=e.replace(/^\s*\[\s\]\s*/,' ').replace(/^\s*\[x\]\s*/,' '),'
          • '+this.atLink(this.emoji(e))+"
          • "):"
          • "+this.atLink(this.emoji(e))+"
          • "},s},r.markdownToCRenderer=function(e,t,i,o){var r="",a=0,n=this.classPrefix;o=o||1;for(var s=0,l=e.length;sa?"":h"):"
        • ",r+='
        • '+c+"
            ",a=h)}var d=t.find(".markdown-toc");if(d.length<1&&"false"===t.attr("previewContainer")){var u='
            ';u=i?'
            '+u+"
            ":u,t.html(u),d=t.find(".markdown-toc")}return i&&d.wrap('

            '),d.html('
              ').children(".markdown-toc-list").html(r.replace(/\r?\n?\\<\/ul\>/g,"")),d},r.tocDropdownMenu=function(t,i){i=i||"Table of Contents";var o=400,r=t.find("."+this.classPrefix+"toc-menu");return r.each(function(){var t=e(this),r=t.children(".markdown-toc"),a='',n=''+a+i+"",s=r.children("ul"),l=s.find("li");r.append(n),l.first().before("
            • "+i+" "+a+"

            • "),t.mouseover(function(){s.show(),l.each(function(){var t=e(this),i=t.children("ul");if(""===i.html()&&i.remove(),i.length>0&&""!==i.html()){var r=t.children("a").first();r.children(".fa").length<1&&r.append(e(a).css({float:"right",paddingTop:"4px"}))}t.mouseover(function(){i.css("z-index",o).show(),o+=1}).mouseleave(function(){i.hide()})})}).mouseleave(function(){s.hide()})}),r},r.filterHTMLTags=function(t,i){if("string"!=typeof t&&(t=new String(t)),"string"!=typeof i)return t;for(var o=i.split("|"),r=o[0].split(","),a=o[1],n=0,s=r.length;n]*)>([^>]*)","igm"),"")}if(void 0!==a){var c=/\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/gi;t="*"===a?t.replace(c,function(e,t,i,o,r){return"<"+t+">"+o+""}):"on*"===a?t.replace(c,function(t,i,o,r,a){var n=e("<"+i+">"+r+""),s=e(t)[0].attributes,l={};e.each(s,function(e,t){'"'!==t.nodeName&&(l[t.nodeName]=t.nodeValue)}),e.each(l,function(e){0===e.indexOf("on")&&delete l[e]}),n.attr(l);var c=void 0!==n[1]?e(n[1]).text():"";return n[0].outerHTML+c}):t.replace(c,function(t,i,o,r){var n=a.split(","),s=e(t);return s.html(r),e.each(n,function(e){s.attr(n[e],null)}),s[0].outerHTML})}return t},r.markdownToHTML=function(t,i){r.$marked=marked;var o=e("#"+t),a=o.settings=e.extend(!0,{gfm:!0,toc:!0,tocm:!1,tocStartLevel:1,tocTitle:"目录",tocDropdown:!1,tocContainer:"",markdown:"",markdownSourceCode:!1,htmlDecode:!1,autoLoadKaTeX:!0,pageBreak:!0,atLink:!0,emailLink:!0,tex:!1,taskList:!1,emoji:!1,flowChart:!1,sequenceDiagram:!1,previewCodeHighlight:!0},i||{}),n=o.find("textarea");n.length<1&&(o.append(""),n=o.find("textarea"));var s=""===a.markdown?n.val():a.markdown,l=[],c={toc:a.toc,tocm:a.tocm,tocStartLevel:a.tocStartLevel,taskList:a.taskList,emoji:a.emoji,tex:a.tex,pageBreak:a.pageBreak,atLink:a.atLink,emailLink:a.emailLink,flowChart:a.flowChart,sequenceDiagram:a.sequenceDiagram,previewCodeHighlight:a.previewCodeHighlight},h={renderer:r.markedRenderer(l,c),gfm:a.gfm,tables:!0,breaks:!0,pedantic:!1,sanitize:!a.htmlDecode,smartLists:!0,smartypants:!0};s=new String(s);var d=marked(s,h);d=r.filterHTMLTags(d,a.htmlDecode),a.markdownSourceCode?n.text(s):n.remove(),o.addClass("markdown-body "+this.classPrefix+"html-preview").append(d);var u=""!==a.tocContainer?e(a.tocContainer):o;if(""!==a.tocContainer&&u.attr("previewContainer",!1),a.toc&&(o.tocContainer=this.markdownToCRenderer(l,u,a.tocDropdown,a.tocStartLevel),(a.tocDropdown||o.find("."+this.classPrefix+"toc-menu").length>0)&&this.tocDropdownMenu(o,a.tocTitle),""!==a.tocContainer&&o.find(".editormd-toc-menu, .editormd-markdown-toc").remove()),a.previewCodeHighlight&&(o.find("pre").addClass("prettyprint linenums"),prettyPrint()),r.isIE8||(a.flowChart&&o.find(".flowchart").flowChart(),a.sequenceDiagram&&o.find(".sequence-diagram").sequenceDiagram({theme:"simple"})),a.tex){var f=function(){o.find("."+r.classNames.tex).each(function(){var t=e(this);katex.render(t.text(),t[0]),t.find(".katex").css("font-size","1.0em")})};!a.autoLoadKaTeX||r.$katex||r.kaTeXLoaded?f():this.loadKaTeX(function(){r.$katex=katex,r.kaTeXLoaded=!0,f()})}return o.getMarkdown=function(){return n.val()},o},r.themes=["default","dark"],r.previewThemes=["default","dark"],r.editorThemes=["default","3024-day","3024-night","ambiance","ambiance-mobile","base16-dark","base16-light","blackboard","cobalt","eclipse","elegant","erlang-dark","lesser-dark","mbo","mdn-like","midnight","monokai","neat","neo","night","paraiso-dark","paraiso-light","pastel-on-dark","rubyblue","solarized","the-matrix","tomorrow-night-eighties","twilight","vibrant-ink","xq-dark","xq-light"],r.loadPlugins={},r.loadFiles={js:[],css:[],plugin:[]},r.loadPlugin=function(e,t,i){t=t||function(){},this.loadScript(e,function(){r.loadFiles.plugin.push(e),t()},i)},r.loadCSS=function(e,t,i){i=i||"head",t=t||function(){};var o=document.createElement("link");o.type="text/css",o.rel="stylesheet",o.onload=o.onreadystatechange=function(){r.loadFiles.css.push(e),t()},o.href=e+".css","head"===i?document.getElementsByTagName("head")[0].appendChild(o):document.body.appendChild(o)},r.isIE="Microsoft Internet Explorer"==navigator.appName,r.isIE8=r.isIE&&"8."==navigator.appVersion.match(/8./i),r.loadScript=function(e,t,i){i=i||"head",t=t||function(){};var o=null;(o=document.createElement("script")).id=e.replace(/[\./]+/g,"-"),o.type="text/javascript",o.src=e+".js",r.isIE8?o.onreadystatechange=function(){o.readyState&&("loaded"!==o.readyState&&"complete"!==o.readyState||(o.onreadystatechange=null,r.loadFiles.js.push(e),t()))}:o.onload=function(){r.loadFiles.js.push(e),t()},"head"===i?document.getElementsByTagName("head")[0].appendChild(o):document.body.appendChild(o)},r.katexURL={css:"/katex/katex.min",js:"/katex/katex.min"},r.kaTeXLoaded=!1,r.loadKaTeX=function(e){r.loadCSS(r.katexURL.css,function(){r.loadScript(r.katexURL.js,e||function(){})})},r.lockScreen=function(t){e("html,body").css("overflow",t?"hidden":"")},r.createDialog=function(t){t=e.extend(!0,{name:"",width:420,height:240,title:"",drag:!0,closed:!0,content:"",mask:!0,maskStyle:{backgroundColor:"#fff",opacity:.1},lockScreen:!0,footer:!0,buttons:!1},t);var i=this,o=this.editor,a=r.classPrefix,n=(new Date).getTime(),s=""===t.name?a+"dialog-"+n:t.name,l=r.mouseOrTouch,c='
              ';""!==t.title&&(c+='
              ",c+=''+t.title+"",c+="
              "),t.closed&&(c+=''),c+='
              '+t.content,(t.footer||"string"==typeof t.footer)&&(c+='"),c+="
              ",c+='
              ',c+='
              ',c+="
              ",o.append(c);var h=o.find("."+s);h.lockScreen=function(o){return t.lockScreen&&(e("html,body").css("overflow",o?"hidden":""),i.resize()),h},h.showMask=function(){return t.mask&&o.find("."+a+"mask").css(t.maskStyle).css("z-index",r.dialogZindex-1).show(),h},h.hideMask=function(){return t.mask&&o.find("."+a+"mask").hide(),h},h.loading=function(e){return h.find("."+a+"dialog-mask")[e?"show":"hide"](),h},h.lockScreen(!0).showMask(),h.show().css({zIndex:r.dialogZindex,border:r.isIE8?"1px solid #ddd":"",width:"number"==typeof t.width?t.width+"px":t.width,height:"number"==typeof t.height?t.height+"px":t.height});var d=function(){h.css({top:(e(window).height()-h.height())/2+"px",left:(e(window).width()-h.width())/2+"px"})};if(d(),e(window).resize(d),h.children("."+a+"dialog-close").bind(l("click","touchend"),function(){h.hide().lockScreen(!1).hideMask()}),"object"==typeof t.buttons){var u=h.footer=h.find("."+a+"dialog-footer");for(var f in t.buttons){var p=t.buttons[f],m=a+f+"-btn";u.append('"),p[1]=e.proxy(p[1],h),u.children("."+m).bind(l("click","touchend"),p[1])}}if(""!==t.title&&t.drag){var g,w,v=h.children("."+a+"dialog-header");t.mask||v.bind(l("click","touchend"),function(){r.dialogZindex+=2,h.css("z-index",r.dialogZindex)}),v.mousedown(function(e){e=e||window.event,g=e.clientX-parseInt(h[0].style.left),w=e.clientY-parseInt(h[0].style.top),document.onmousemove=x});var k=function(e){e.removeClass(a+"user-unselect").off("selectstart")},b=function(e){e.addClass(a+"user-unselect").on("selectstart",function(e){return!1})},x=function(t){t=t||window.event;var i,o,r=parseInt(h[0].style.left),a=parseInt(h[0].style.top);r>=0?r+h.width()<=e(window).width()?i=t.clientX-g:(i=e(window).width()-h.width(),document.onmousemove=null):(i=0,document.onmousemove=null),a>=0?o=t.clientY-w:(o=0,document.onmousemove=null),document.onselectstart=function(){return!1},b(e("body")),b(h),h[0].style.left=i+"px",h[0].style.top=o+"px"};document.onmouseup=function(){k(e("body")),k(h),document.onselectstart=null,document.onmousemove=null},v.touchDraggable=function(){var t=null;this.bind("touchstart",function(i){var o=i.originalEvent,r=e(this).parent().position();t={x:o.changedTouches[0].pageX-r.left,y:o.changedTouches[0].pageY-r.top}}).bind("touchmove",function(i){i.preventDefault();var o=i.originalEvent;e(this).parent().css({top:o.changedTouches[0].pageY-t.y,left:o.changedTouches[0].pageX-t.x})})},v.touchDraggable()}return r.dialogZindex+=2,e("body").removeAttr("style"),h},r.mouseOrTouch=function(e,t){t=t||"touchend";var i=e=e||"click";try{document.createEvent("TouchEvent"),i=t}catch(e){}return i},r.dateFormat=function(e){e=e||"";var t=function(e){return e<10?"0"+e:e},i=new Date,o=i.getFullYear(),r=o.toString().slice(2,4),a=t(i.getMonth()+1),n=t(i.getDate()),s=i.getDay(),l=t(i.getHours()),c=t(i.getMinutes()),h=t(i.getSeconds()),d=t(i.getMilliseconds()),u="",f=r+"-"+a+"-"+n,p=o+"-"+a+"-"+n,m=l+":"+c+":"+h;switch(e){case"UNIX Time":u=i.getTime();break;case"UTC":u=i.toUTCString();break;case"yy":u=r;break;case"year":case"yyyy":u=o;break;case"month":case"mm":u=a;break;case"cn-week-day":case"cn-wd":u="星期"+["日","一","二","三","四","五","六"][s];break;case"week-day":case"wd":u=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][s];break;case"day":case"dd":u=n;break;case"hour":case"hh":u=l;break;case"min":case"ii":u=c;break;case"second":case"ss":u=h;break;case"ms":u=d;break;case"yy-mm-dd":u=f;break;case"yyyy-mm-dd":u=p;break;case"yyyy-mm-dd h:i:s ms":case"full + ms":u=p+" "+m+" "+d;break;case"full":case"yyyy-mm-dd h:i:s":default:u=p+" "+m}return u},r}}),window._whenPasterDoUpload=function(e,t,i){var o,r,a,n=e.clipboardData,s=0;if(n){if(!(o=n.items))return;for(r=o[0],a=n.types||[];s p { line-height: 25px; @@ -71,7 +72,10 @@ html, body { /* 某些情况下,被cm盖住了 */ z-index: 99; } - +/* 解决鼠标框选时,左边第一列没高亮的问题 */ +.CodeMirror .CodeMirror-lines pre.CodeMirror-line, .CodeMirror .CodeMirror-lines pre.CodeMirror-line-like { + padding: 0 12px ; +} /* antd扩展 */ diff --git a/public/react/src/App.js b/public/react/src/App.js index fbb9ac7b0..17ee34255 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -37,7 +37,7 @@ import {MuiThemeProvider, createMuiTheme} from 'material-ui/styles'; import history from './history'; -import {SnackbarHOC} from 'educoder' +import {SnackbarHOC, configShareForIndex} from 'educoder' import {initAxiosInterceptors} from './AppConfig' @@ -222,6 +222,12 @@ const InfosIndex = Loadable({ loader: () => import('./modules/user/usersInfo/InfosIndex'), loading: Loading, }) +// 题库 +const BanksIndex = Loadable({ + loader: () => import('./modules/user/usersInfo/banks/BanksIndex'), + loading: Loading, +}) + // 教学案例 const MoopCases = Loadable({ @@ -245,6 +251,17 @@ const Messagerouting= Loadable({ loader: () => import('./modules/message/js/Messagerouting'), loading: Loading, }) + +const Topicbank= Loadable({ + loader: () => import('./modules/topic_bank/Topic_bank'), + loading: Loading, +}) + +const Help = Loadable({ + loader: () => import('./modules/help/Help'), + loading: Loading, +}) + class App extends Component { constructor(props) { super(props) @@ -285,15 +302,18 @@ class App extends Component { if (window.wx) { const wx = window.wx const url = '/wechats/js_sdk_signature.json' + const currentUrl = window.location.href.split('#')[0] + // window.encodeURIComponent() axios.post(url, { - url: 'http://pre-newweb.educoder.net', + url: window.__testUrl || currentUrl, }).then((response) => { + console.log('got res') const data = response.data; wx.config({ debug: false, appId: data.appid, timestamp: data.timestamp, - nonceStr: data.nonceStr, + nonceStr: data.noncestr, signature: data.signature, jsApiList: [ 'onMenuShareTimeline',// @@ -305,23 +325,26 @@ class App extends Component { ] }); wx.ready(function () { - var shareData = { - title: '这是是分享标题', - desc: '这是是摘要', - link: 'http://pre-newweb.educoder.net', - imgUrl: 'http://pre-newweb.educoder.net/images/educoder/index/subject/subject15.jpg' - }; - - wx.onMenuShareAppMessage(shareData);//分享给好友 - wx.onMenuShareTimeline(shareData);//分享到朋友圈 - wx.onMenuShareQQ(shareData);//分享给手机QQ - wx.onMenuShareWeibo(shareData);//分享腾讯微博 - wx.onMenuShareQZone(shareData);//分享到QQ空间 - - + console.log('wx is ready') + // var shareData = { + // title: 'EduCoder - 首页', + // desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台,提供企业级工程实训,以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动,将传统的知识传授和时兴的工程实战一体化。', + // link: currentUrl, + // imgUrl: window.__testImageUrl + // || (currentUrl.endsWith('/') ? currentUrl : currentUrl + '/') + 'react/build/images/share_logo_icon.jpg' + // }; + // wx.onMenuShareAppMessage(shareData);//分享给好友 + // wx.onMenuShareTimeline(shareData);//分享到朋友圈 + // wx.onMenuShareQQ(shareData);//分享给手机QQ + // wx.onMenuShareWeibo(shareData);//分享腾讯微博 + // wx.onMenuShareQZone(shareData);//分享到QQ空间 + + configShareForIndex('/') }); wx.error(function (res) { + console.log('wx is error') + console.log(res) //alert(res.errMsg);//错误提示 }); @@ -330,8 +353,17 @@ class App extends Component { }) } } + disableVideoContextMenu = () => { + window.$( "body" ).on( "mousedown", "video", function(event) { + if(event.which === 3) { + window.$('video').bind('contextmenu',function () { return false; }); + } else { + window.$('video').unbind('contextmenu'); + } + }); + } componentDidMount() { - + this.disableVideoContextMenu(); // force an update if the URL changes history.listen(() => { @@ -388,6 +420,22 @@ class App extends Component { + {/*题库*/} + { + + return () + } + }> + {/*题库*/} + { + + return () + } + }> {/*众包创新*/} {/*认证*/} @@ -416,6 +464,13 @@ class App extends Component { } }> + { + return () + } + }> + @@ -471,6 +526,10 @@ class App extends Component { (props)=>() } > + () + }/> diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 939d2cdaa..a89eacfa1 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -10,7 +10,7 @@ broadcastChannelOnmessage('refreshPage', () => { }) function locationurl(list){ - debugger + if (window.location.port === "3007") { } else { @@ -45,6 +45,7 @@ export function initAxiosInterceptors(props) { proxy="http://47.96.87.25:48080" // wy proxy="https://pre-newweb.educoder.net" + proxy="https://test-newweb.educoder.net" // wy // proxy="http://192.168.2.63:3001" diff --git a/public/react/src/CustomLoadable.js b/public/react/src/CustomLoadable.js new file mode 100644 index 000000000..31e0e8a17 --- /dev/null +++ b/public/react/src/CustomLoadable.js @@ -0,0 +1,12 @@ +import Loadable from 'react-loadable'; + +import Loading from "./Loading"; + +const CustomLoadable = (loader, loading = Loading) => { + return Loadable({ + loader, + loading + }) +} + +export default CustomLoadable \ No newline at end of file diff --git a/public/react/src/common/Env.js b/public/react/src/common/Env.js index 283e82c48..c80497509 100644 --- a/public/react/src/common/Env.js +++ b/public/react/src/common/Env.js @@ -3,4 +3,6 @@ export function isDev() { } // const isMobile -export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); \ No newline at end of file +export const isMobile = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())); + +// const isWeiXin = (/MicroMessenger/i.test(navigator.userAgent.toLowerCase())); diff --git a/public/react/src/common/SnackbarHOC.js b/public/react/src/common/SnackbarHOC.js index d66b697ca..fe5bc4901 100644 --- a/public/react/src/common/SnackbarHOC.js +++ b/public/react/src/common/SnackbarHOC.js @@ -48,7 +48,17 @@ export function SnackbarHOC(options = {}) { snackbarHorizontal: horizontal, }) } - + //个别情况需要走 + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } render() { const { snackbarOpen, snackbarText, snackbarHorizontal, snackbarVertical } = this.state; @@ -70,7 +80,7 @@ export function SnackbarHOC(options = {}) { resumeHideDuration={2000} message={{this.state.snackbarText}} /> - + diff --git a/public/react/src/common/UrlTool.js b/public/react/src/common/UrlTool.js index 3d3053805..3ad52f264 100644 --- a/public/react/src/common/UrlTool.js +++ b/public/react/src/common/UrlTool.js @@ -1,10 +1,10 @@ const isDev = window.location.port == 3007; -export const TEST_HOST = "https://pre-newweb.educoder.net" +export const TEST_HOST = "https://test-newweb.educoder.net" export function getImageUrl(path) { // https://www.educoder.net // https://testbdweb.trustie.net // const local = 'http://localhost:3000' - const local = 'https://pre-newweb.educoder.net' + const local = 'https://test-newweb.educoder.net' if (isDev) { return `${local}/${path}` } @@ -12,7 +12,7 @@ export function getImageUrl(path) { } export function setImagesUrl(path){ - const local = 'https://pre-newweb.educoder.net' + const local = 'https://test-newweb.educoder.net' let firstStr=path.substr(0,1); // console.log(firstStr); if(firstStr=="/"){ @@ -31,7 +31,7 @@ export function getUrl(path, goTest) { // testbdweb.educoder.net testbdweb.trustie.net // const local = goTest ? 'https://testeduplus2.educoder.net' : 'http://localhost:3000' // const local = 'https://testeduplus2.educoder.net' - const local = 'https://pre-newweb.educoder.net' + const local = 'https://test-newweb.educoder.net' if (isDev) { return `${local}${path?path:''}` } @@ -56,7 +56,7 @@ export function getUploadActionUrl(path, goTest) { return `${getUrl()}/api/attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` } export function getUploadActionUrlOfAuth(id) { - return `${getUrl()}/api/users/accounts/${id}/auth_attachments.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` + return `${getUrl()}/api/users/accounts/${id}/auth_attachment.json${isDev ? `?debug=${window._debugType || 'admin'}` : ''}` } export function test(path) { diff --git a/public/react/src/common/educoder.js b/public/react/src/common/educoder.js index 5b1d7ac28..fcd0ba7e4 100644 --- a/public/react/src/common/educoder.js +++ b/public/react/src/common/educoder.js @@ -20,6 +20,8 @@ export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, ap downloadFile, sortDirections } from './TextUtil' export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil' +export { configShareForIndex, configShareForPaths, configShareForShixuns, configShareForCourses, configShareForCustom } from './util/ShareUtil' + export { isDev as isDev, isMobile } from './Env' export { toStore as toStore, fromStore as fromStore } from './Store' diff --git a/public/react/src/common/util/ShareUtil.js b/public/react/src/common/util/ShareUtil.js new file mode 100644 index 000000000..9a83db552 --- /dev/null +++ b/public/react/src/common/util/ShareUtil.js @@ -0,0 +1,85 @@ +const host = window.location.protocol + '//' + window.location.host +const wx = window.wx +function share(shareData) { + try { + wx.onMenuShareAppMessage(shareData);//分享给好友 + wx.onMenuShareTimeline(shareData);//分享到朋友圈 + wx.onMenuShareQQ(shareData);//分享给手机QQ + wx.onMenuShareWeibo(shareData);//分享腾讯微博 + wx.onMenuShareQZone(shareData);//分享到QQ空间 + } catch(e) { + console.log(e) + } +} + +/** + 实践课程 平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系,通过由浅入深的实训路径,帮助学生快速提升实战能力。 + 实训项目 覆盖不同专业的IT实验和实训,每周更新,无需配置本机实验环境,随时随地开启企业级真实实训。 + 翻转课堂 自动评测实训任务,支持技能统计,提供教学活动分析报告,减轻教师和助教的辅导压力,免去作业发布和批改的困扰,实时了解学生学习情况,全面提升教师施教效率和水平。 + 单个课程和实训 获取课程/实训的简介 该课程或者实训展示的缩略图 + + */ +export function configShareForIndex (path) { + if (!wx) return; + var shareData = { + title: 'EduCoder - 首页', + desc: 'Educoder是一个面向计算机类的互联网IT教育和实战平台,提供企业级工程实训,以实现工程化专业教学的自动化和智能化。高校和企业人员可以在此开展计算机实践性教学活动,将传统的知识传授和时兴的工程实战一体化。', + link: host + (path || ''), + imgUrl: window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) +} +export function configShareForPaths () { + if (!wx) return; + console.log('configShareForPaths', host) + var shareData = { + title: 'EduCoder - 实践课程', + desc: '平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系,通过由浅入深的实训路径,帮助学生快速提升实战能力。', + link: `${host}/paths`, + imgUrl: window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) +} +export function configShareForShixuns () { + if (!wx) return; + console.log('configShareForShixuns', host) + + var shareData = { + title: 'EduCoder - 实训项目', + desc: '覆盖不同专业的IT实验和实训,每周更新,无需配置本机实验环境,随时随地开启企业级真实实训。', + link: `${host}/shixuns`, + imgUrl: window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) +} +export function configShareForCourses () { + if (!wx) return; + console.log('configShareForCourses', host) + + var shareData = { + title: 'EduCoder - 翻转课堂', + desc: '自动评测实训任务,支持技能统计,提供教学活动分析报告,减轻教师和助教的辅导压力,免去作业发布和批改的困扰,实时了解学生学习情况,全面提升教师施教效率和水平。', + link: `${host}/courses`, + imgUrl: window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) +} + +// detail +export function configShareForCustom (title, desc, path, imgUrl) { + if (!wx) return; + console.log('configShareForCustom', host) + + var shareData = { + title: title, + desc: desc, + link: `${host}/${path}`, + imgUrl: imgUrl || window.__testImageUrl + || host + '/react/build/images/share_logo_icon.jpg' + }; + share(shareData) +} diff --git a/public/react/src/context/TPIContextProvider.js b/public/react/src/context/TPIContextProvider.js index 3fbdb6ed1..ee01c3c72 100644 --- a/public/react/src/context/TPIContextProvider.js +++ b/public/react/src/context/TPIContextProvider.js @@ -32,7 +32,7 @@ import _ from 'lodash' import TPIContext from './TPIContext' import { EDU_ADMIN, EDU_SHIXUN_MANAGER, EDU_SHIXUN_MEMBER, EDU_CERTIFICATION_TEACHER - , EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS} from 'educoder' + , EDU_GAME_MANAGER, EDU_TEACHER, EDU_NORMAL, EDU_BUSINESS, CNotificationHOC } from 'educoder' import { MuiThemeProvider, createMuiTheme, withStyles } from 'material-ui/styles'; import MUIDialogStyleUtil from '../modules/page/component/MUIDialogStyleUtil' @@ -174,7 +174,7 @@ class TPIContextProvider extends Component { } let testPath = '' if (window.location.port == 3007) { - testPath = 'http://pre-newweb.educoder.net' + testPath = 'http://test-newweb.educoder.net' } // var url = `${testPath}/api/v1/games/${ game.identifier }/cost_time` var url = `${testPath}/api/tasks/${ game.identifier }/cost_time` @@ -268,12 +268,14 @@ pop_box_new(htmlvalue, 480, 182); }); } - onPathChange(index) { + onPathChange(index, callback) { let { challenge } = this.state; // challenge = Object.assign({}, challenge) // challenge.pathIndex = index; this.setState({ challenge: update(challenge, {pathIndex: { $set: index }}), + }, () => { + callback && callback() }) // TODO load new path content } @@ -877,6 +879,7 @@ pop_box_new(htmlvalue, 480, 182); return ( import('./graduation/tasks/GraduationTaskssettinglist'), + loader: () => import('./graduation/tasks/GraduationTaskDetail'), loading: Loading, }) @@ -264,34 +264,12 @@ const GraduationTasksSubmiteditApp=Loadable({ loader: () => import('./graduation/tasks/GraduationTasksSubmitedit'), loading: Loading, }) -//普通作业题库详情 -const Generaljobbankdetails =Loadable({ - loader: () => import('../../modules/courses/questionbank/Generaljobbankdetails'), - loading: Loading, -}); -//分组作业题库详情 -const GroupjobbankPage =Loadable({ - loader: () => import('../../modules/courses/groupjobbank/GroupjobbankPage'), - loading: Loading, -}); -//毕设选题详情 -const CompletetopicdePage =Loadable({ - loader: () => import('../../modules/courses/comtopicdetails/CompletetopicdePage'), - loading: Loading, -}); -//毕设任务详情 -const Completetaskpage =Loadable({ - loader: () => import('../../modules/courses/completetaskdetails/Completetaskpage'), - loading: Loading, -}); - //排序 const Ordering=Loadable({ loader: () => import('../../modules/courses/ordering/Ordering'), loading: Loading, }); - class CoursesIndex extends Component{ constructor(props) { super(props) @@ -318,15 +296,16 @@ class CoursesIndex extends Component{ componentDidMount(){ // this.updataleftNav() - this.historyArray = [] + this.historyArray = [window.location.pathname]; + this.props.history.listen( location => { - console.log(location) - this.historyArray.unshift(location.pathname) + console.log(location); + this.historyArray.unshift(window.location.pathname); this.historyArray.length = 2; //Do your stuff here }); } - + //更新左边课堂导航 updataleftNav=()=>{ let query=this.props.location.pathname let {isaloadtype}=this.state; @@ -478,37 +457,12 @@ class CoursesIndex extends Component{ // console.log(commons) return ( - {/*排序*/} - () - } - > - - {/*毕设任务题库详情*/} - () - } - > - {/*毕设内容题库详情*/} - () - } - > - {/*分组作业题库详情*/} - () - } - > - {/* 普通作业题库详情*/} - () - } - > + {/*排序*/} + () + } + > {/* 资源列表页 */} {/* 新建作品 */} - () } > {/* 修改作品 */} - () } @@ -589,7 +543,7 @@ class CoursesIndex extends Component{ {/* 设置毕设任务 https://www.trustie.net/issues/19981 */} - () } @@ -597,19 +551,18 @@ class CoursesIndex extends Component{ () - }> + render={ + (props) => () + }> */} - () } > - {/* 修改毕设任务 https://www.trustie.net/issues/19981 */} - + this.comyslElearning(i)}/> {/*right_concent*/} @@ -258,7 +268,7 @@ class ListPageIndex extends Component{ () + (props) => (this.comyslElearning(i)} />) } > diff --git a/public/react/src/modules/courses/Resource/Fileslistitem.js b/public/react/src/modules/courses/Resource/Fileslistitem.js index b06ab3dc1..4e8e89567 100644 --- a/public/react/src/modules/courses/Resource/Fileslistitem.js +++ b/public/react/src/modules/courses/Resource/Fileslistitem.js @@ -30,7 +30,8 @@ class Fileslistitem extends Component{ showfiles=(list)=>{ if(list.is_history_file===false){ // this.props.DownloadFileA(list.title,list.url) - window.location.href=list.url; + //window.location.href=list.url; + window.open(list.url, '_blank'); }else{ let {discussMessage,coursesId}=this.props let file_id=discussMessage.id @@ -49,7 +50,7 @@ class Fileslistitem extends Component{ // // } // this.props.DownloadFileA(result.data.title,result.data.url) - window.location.href=list.url; + window.open(list.url, '_blank'); }else{ this.setState({ Showoldfiles:true, diff --git a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js index 698fbd398..04ccb3ea1 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js @@ -254,7 +254,7 @@ class CommonWorkAppraise extends Component{ 关联项目
              - {project_info.name} + {project_info.name}
              } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js index 5693b3788..b5fb8b047 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js @@ -391,7 +391,7 @@ class CommonWorkDetailIndex extends Component{ { work_statuses && work_statuses.indexOf('补交作品') != -1 && { this.props.toWorkPostPage(this.props.match.params, null, true, work_id)}}> + onClick={() => { this.props.toWorkPostPage(this.props.match.params)}}> 补交作品 } {work_statuses && work_statuses.indexOf('修改作品') != -1 && { diff --git a/public/react/src/modules/courses/busyWork/NewWork.js b/public/react/src/modules/courses/busyWork/NewWork.js index 8000de59f..e11eca9e2 100644 --- a/public/react/src/modules/courses/busyWork/NewWork.js +++ b/public/react/src/modules/courses/busyWork/NewWork.js @@ -4,250 +4,125 @@ import axios from 'axios' import '../css/busyWork.css' import '../css/Courses.css' import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll - , getUploadActionUrl } from 'educoder' + , getUploadActionUrl } from 'educoder' import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; import CBreadcrumb from '../common/CBreadcrumb' +import NewWorkForm from './NewWorkForm' const confirm = Modal.confirm; const $ = window.$ const MAX_TITLE_LENGTH = 60; class NewWork extends Component{ - constructor(props){ - super(props); - this.contentMdRef = React.createRef(); - this.answerMdRef = React.createRef(); - - this.state={ - title_value:"", - title_num: 0, - contentFileList: [], - answerFileList: [], - workLoaded: false, - base_on_project: true, - category: {}, - min_num: 2, - max_num: 10, - } - } - componentDidMount () { - let {typeId, coursesId, pageType, workId}=this.props.match.params; - const isEdit = pageType === "edit" - this.isEdit = isEdit; - if (isEdit) { - this.fetchWork(workId) - } else { - this.fetchCourseData(coursesId) - } - } - fetchCourseData = (courseId) => { - const isGroup = this.props.isGroup() - const url = `/courses/${courseId}/homework_commons/new.json?type=${isGroup ? 3 : 1}` - axios.get(url, { - }) - .then((response) => { - if (response.data.course_name) { - const data = response.data; - this.setState({ - course_id: data.course_id, - course_name: data.course_name, - category: data.category, - - }) - } - }) - .catch(function (error) { - console.log(error); - }); - } - fetchWork = (workId) => { - const url = `/homework_commons/${workId}/edit.json` - axios.get(url, { - }) - .then((response) => { - if (response.data.name) { - const data = response.data; - - const contentFileList = data.attachments.map(item => { - return { - id: item.id, - uid: item.id, - name: appendFileSizeToUploadFile(item), - url: item.url, - filesize: item.filesize, - status: 'done' - } - }) - const answerFileList = data.ref_attachments.map(item => { - return { - id: item.id, - uid: item.id, - name: appendFileSizeToUploadFile(item), - url: item.url, - filesize: item.filesize, - status: 'done' - } - }) - - this.setState({ - ...data, - // course_id: data.course_id, - // course_name: data.course_name, - // category: data.category, - title_num: parseInt(data.name.length), - workLoaded: true, - init_min_num: data.min_num, - init_max_num: data.max_num, - // description: data.description, - reference_answer: data.reference_answer, - contentFileList, - answerFileList, - }, () => { - setTimeout(() => { - this.contentMdRef.current.setValue(data.description || '') - this.answerMdRef.current.setValue(data.reference_answer || '') - - }, 2000) - - this.props.form.setFieldsValue({ - title: data.name, - description: data.description || '', - reference_answer: data.reference_answer || '', - }); - - }) - - } - }) - .catch(function (error) { - console.log(error); - }); - } - - // 输入title - changeTitle=(e)=>{ - console.log(e.target.value.length); - this.setState({ - title_num: parseInt(e.target.value.length) - }) - } - handleSubmit = () => { - const courseId = this.state.course_id || this.props.match.params.coursesId ; - - this.props.form.validateFieldsAndScroll((err, values) => { - console.log(values) - const mdContnet = this.contentMdRef.current.getValue().trim(); - console.log(mdContnet) - values.description = mdContnet; - // return; - - {/* max={has_commit ? init_min_num : null } */} - {/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */} - // 已有提交作品,人数范围只能扩大 - const { has_commit, max_num, init_max_num, min_num, init_min_num } = this.state; - if (has_commit) { - if (max_num < init_max_num || min_num > init_min_num) { - this.props.showNotification(`已有提交作品,人数范围只能扩大(原设置为:${init_min_num} - ${init_max_num})`) - return; - } - } - - // const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet - if (!err) { - if (this.isEdit) { - this.doEdit(courseId, values) - } else { - this.doNew(courseId, values) - } - - } else { - $("html").animate({ scrollTop: $('html').scrollTop() - 100 }) - } - }) - } - doEdit = (courseId, values) => { - const workId = this.props.match.params.workId - const newUrl = `/homework_commons/${workId}.json` - - let attachment_ids = this.state.contentFileList.map(item => { - return item.response ? item.response.id : item.id - }) - let reference_attachment_ids = this.state.answerFileList.map(item => { - return item.response ? item.response.id : item.id - }) - - const { min_num, max_num, base_on_project, category } = this.state - const isGroup = this.props.isGroup() - axios.put(newUrl, { - type: isGroup ? 3 : 1, - name: values.title, - description: values.description, - reference_answer: values.reference_answer, - attachment_ids, - reference_attachment_ids, - - min_num, - max_num, - base_on_project - }) - .then((response) => { - if (response.data.status == 0) { - this.props.showNotification('保存成功') - this.props.toWorkListPage(this.props.match.params, workId) - } - }) - .catch(function (error) { - console.log(error); - }); - } - doNew = (courseId, values) => { - const newUrl = `/courses/${courseId}/homework_commons.json` - - let attachment_ids = this.state.contentFileList.map(item => { - return item.response ? item.response.id : item.id - }) - let reference_attachment_ids = this.state.answerFileList.map(item => { - return item.response ? item.response.id : item.id - }) - const isGroup = this.props.isGroup() - const { min_num, max_num, base_on_project, category } = this.state - - axios.post(newUrl, { - type: isGroup ? 3 : 1, - name: values.title, - description: values.description, - reference_answer: values.reference_answer, - attachment_ids, - reference_attachment_ids, + constructor(props){ + super(props); + this.contentMdRef = React.createRef(); + this.answerMdRef = React.createRef(); + + this.state={ + category: {}, + course_name: '' + } + } + componentDidMount () { + let {typeId, coursesId, pageType, workId}=this.props.match.params; + const isEdit = pageType === "edit" + this.isEdit = isEdit; + if (isEdit) { + this.fetchWork(workId) + } else { + this.fetchCourseData(coursesId) + } + } + fetchCourseData = (courseId) => { + const isGroup = this.props.isGroup() + const url = `/courses/${courseId}/homework_commons/new.json?type=${isGroup ? 3 : 1}` + axios.get(url, { + }) + .then((response) => { + if (response.data.course_name) { + const data = response.data; + this.setState({ + course_id: data.course_id, + course_name: data.course_name, + category: data.category, + + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + fetchWork = (workId) => { + const url = `/homework_commons/${workId}/edit.json` + axios.get(url, { + }) + .then((response) => { + if (response.data.name) { + const data = response.data; + data.isEdit = this.isEdit + this.setState({ + course_id: data.course_id, + course_name: data.course_name, + category: data.category, + }) + this.newWorkFormRef.initValue(response.data) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + onCancel = () => { + this.props.toListPage(this.props.match.params, this.state.category.category_id) + } + + doEdit = (params) => { + const workId = this.props.match.params.workId + const newUrl = `/homework_commons/${workId}.json` + + axios.put(newUrl, params) + .then((response) => { + if (response.data.status == 0) { + this.props.showNotification('保存成功') + this.props.toWorkListPage(this.props.match.params, workId) + } + }) + .catch(function (error) { + console.log(error); + }); + } + doNew = (params) => { + const coursesId = this.props.match.params.coursesId + const newUrl = `/courses/${coursesId}/homework_commons.json` + + axios.post(newUrl, params) + .then((response) => { + if (response.data.status == 0) { + this.props.showNotification('保存成功') + this.props.toWorkListPage(this.props.match.params, response.data.homework_id) + } + }) + .catch(function (error) { + console.log(error); + }); + } - min_num, - max_num, - base_on_project - }) - .then((response) => { - if (response.data.status == 0) { - this.props.showNotification('保存成功') - this.props.toWorkListPage(this.props.match.params, response.data.homework_id) - } - }) - .catch(function (error) { - console.log(error); - }); - } + handleContentUploadChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let contentFileList = info.fileList; + this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); + } + } + handleAnswerUploadChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let answerFileList = info.fileList; + this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); + } + } - handleContentUploadChange = (info) => { - if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { - let contentFileList = info.fileList; - this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); - } - } - handleAnswerUploadChange = (info) => { - if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { - let answerFileList = info.fileList; - this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); - } - } - - onAttachmentRemove = (file, stateName) => { + onAttachmentRemove = (file, stateName) => { if(!file.percent || file.percent == 100){ this.props.confirm({ content: '是否确认删除?', @@ -264,293 +139,69 @@ class NewWork extends Component{ return false; } - } - deleteAttachment = (file, stateName) => { - // 初次上传不能直接取uid - const url = `/attachments/${file.response ? file.response.id : file.uid}.json` - axios.delete(url, { - }) - .then((response) => { - if (response.data) { - const { status } = response.data; - if (status == 0) { - console.log('--- success') - - this.setState((state) => { - const index = state[stateName].indexOf(file); - const newFileList = state[stateName].slice(); - newFileList.splice(index, 1); - return { - [stateName]: newFileList, - }; - }); - } - } - }) - .catch(function (error) { - console.log(error); - }); - } - max_num_change = (val) => { - if (val < 2) { - this.setState({ - max_num: 2, - }) - return; - } - const { min_num } = this.state; - this.setState({ - max_num: val, - min_num: val <= min_num ? val - 1 : min_num - }) - } - min_num_change = (val) => { - this.setState({ min_num: val }) - } - base_on_project_change = () => { - this.setState({ base_on_project: !this.state.base_on_project }) - } + } - render(){ - let {typeId,coursesId,pageType}=this.props.match.params; - const { getFieldDecorator } = this.props.form; - const isGroup = this.props.isGroup() - const moduleName = !isGroup? "普通作业":"分组作业"; - const moduleEngName = this.props.getModuleName() - let{ - title_value, contentFileList, answerFileList, max_num, min_num, base_on_project, - init_max_num, init_min_num, - title_num, course_name, category, has_commit, has_project - }=this.state - const { current_user } = this.props + render(){ + let {typeId,coursesId,pageType}=this.props.match.params; - const courseId = this.state.course_id || this.props.match.params.coursesId ; - const isEdit = this.isEdit; - if ((isEdit == undefined || isEdit) && !this.state.workLoaded) { - return '' - } - const uploadProps = { - width: 600, - fileList: contentFileList, - multiple: true, - // https://github.com/ant-design/ant-design/issues/15505 - // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // showUploadList: false, - action: `${getUploadActionUrl()}`, - onChange: this.handleContentUploadChange, - onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'), - beforeUpload: (file) => { - console.log('beforeUpload', file.name); - const isLt150M = file.size / 1024 / 1024 < 150; - if (!isLt150M) { - this.props.showNotification('文件大小必须小于150MB!'); - } - return isLt150M; - }, - }; - const answerUploadProps = { - width: 600, - fileList: answerFileList, - multiple: true, - // https://github.com/ant-design/ant-design/issues/15505 - // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 - // showUploadList: false, - action: `${getUrl()}/api/attachments.json`, - onChange: this.handleAnswerUploadChange, - onRemove: (file) => this.onAttachmentRemove(file, 'answerFileList'), - beforeUpload: (file) => { - console.log('beforeUpload', file.name); - const isLt150M = file.size / 1024 / 1024 < 150; - if (!isLt150M) { - this.props.showNotification('文件大小必须小于150MB!'); - } - return isLt150M; - }, - }; + const isGroup = this.props.isGroup() + const moduleName = !isGroup? "普通作业":"分组作业"; + const moduleEngName = this.props.getModuleName() + let{ + course_name, category + }=this.state + const { current_user } = this.props - return( -
              -
              - {/*

              - {course_name} - > - {typeId==1 ?"普通作业":"分组作业"} - > - {pageType==="new"?"新建":"编辑"} -

              */} - - -

              - {this.isEdit ?"编辑":"新建"}{ moduleName } - {/* history.goBack() - this.props.toListPage(this.props.match.params, category.category_id)} - */} - this.props.history.goBack()}> - 返回 - -

              -
              - {/* onSubmit={this.handleSubmit} */} - -
              - - {getFieldDecorator('title', { - rules: [{ - required: true, message: '请输入标题' - }], - })( - - )} - - - - { - {getFieldDecorator('description', { - rules: [{ - required: true, message: '请输入作业内容和要求' - }], - })( - - )} - } - - - (单个文件150M以内) - - - - { isGroup && - - {getFieldDecorator('personNum', { - rules: [{ - required: false - // required: true, message: '请输入最小人数和最大人数' - }], - })( -
              -

              - - {/* max={has_commit ? init_min_num : null } */} - - - - ~ - {/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */} - - - - -

              -

              - - 基于项目实施 - - - -

              -
              - )} -
              - } - - {getFieldDecorator('reference_answer', { - rules: [{ - required: false - }], - })( - - )} - - - (单个文件150M以内) - - - - - - -
              -
              -
              - ) - } + ` + } + + {this.newWorkFormRef = ref}} + > + + + + ) + } } -const WrappedBoardsNew = Form.create({ name: 'NewWork' })(NewWork); -export default WrappedBoardsNew; \ No newline at end of file + +export default NewWork; \ No newline at end of file diff --git a/public/react/src/modules/courses/busyWork/NewWorkForm.js b/public/react/src/modules/courses/busyWork/NewWorkForm.js new file mode 100644 index 000000000..f5d4d9eb4 --- /dev/null +++ b/public/react/src/modules/courses/busyWork/NewWorkForm.js @@ -0,0 +1,529 @@ +import React,{ Component } from "react"; +import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Modal } from "antd"; +import axios from 'axios' +import '../css/busyWork.css' +import '../css/Courses.css' +import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder' +import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; +import CBreadcrumb from '../common/CBreadcrumb' + +const confirm = Modal.confirm; +const $ = window.$ +const MAX_TITLE_LENGTH = 60; + +/** + 需要注意的props + isGroup +*/ +class NewWorkForm extends Component{ + constructor(props){ + super(props); + this.contentMdRef = React.createRef(); + this.answerMdRef = React.createRef(); + + this.state={ + title_value:"", + title_num: 0, + contentFileList: [], + answerFileList: [], + workLoaded: false, + base_on_project: true, + category: {}, + min_num: 2, + max_num: 10, + } + } + initValue = (data) => { + if (data.isEdit) { + const contentFileList = data.attachments.map(item => { + return { + id: item.id, + uid: item.id, + name: appendFileSizeToUploadFile(item), + url: item.url, + filesize: item.filesize, + status: 'done' + } + }) + const answerFileList = data.ref_attachments.map(item => { + return { + id: item.id, + uid: item.id, + name: appendFileSizeToUploadFile(item), + url: item.url, + filesize: item.filesize, + status: 'done' + } + }) + + this.setState({ + ...data, + // course_id: data.course_id, + // course_name: data.course_name, + // category: data.category, + title_num: parseInt(data.name.length), + workLoaded: true, + init_min_num: data.min_num, + init_max_num: data.max_num, + // description: data.description, + reference_answer: data.reference_answer, + contentFileList, + answerFileList, + }, () => { + setTimeout(() => { + this.contentMdRef.current.setValue(data.description || '') + this.answerMdRef.current.setValue(data.reference_answer || '') + + }, 2000) + + this.props.form.setFieldsValue({ + title: data.name, + description: data.description || '', + reference_answer: data.reference_answer || '', + }); + + }) + } else { // new + + } + } + + + // 输入title + changeTitle=(e)=>{ + console.log(e.target.value.length); + this.setState({ + title_num: parseInt(e.target.value.length) + }) + } + handleSubmit = () => { + const courseId = this.state.course_id || this.props.match.params.coursesId ; + + this.props.form.validateFieldsAndScroll((err, values) => { + if(err && err.personNum) delete err.personNum; + console.log(values) + const mdContnet = this.contentMdRef.current.getValue().trim(); + console.log(mdContnet) + values.description = mdContnet; + // return; + + {/* max={has_commit ? init_min_num : null } */} + {/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */} + // 已有提交作品,人数范围只能扩大 + const { has_commit, max_num, init_max_num, min_num, init_min_num } = this.state; + const isGroup = this.props.isGroup() + if (isGroup) { + if (!min_num) { + this.props.showNotification('最小人数不能为空'); + return; + } else if (min_num < 1) { + this.props.showNotification('最小人数不能小于1'); + return; + } else if (!max_num) { + this.props.showNotification('最大人数不能为空'); + return; + } else if (max_num < min_num) { + this.props.showNotification('最大人数不能小于最小人数'); + return; + } + + if (has_commit) { + if (max_num < init_max_num || min_num > init_min_num) { + this.props.showNotification(`已有提交作品,人数范围只能扩大(原设置为:${init_min_num} - ${init_max_num})`) + return; + } + } + } + + // const errKeys = Object.keys(err); // || errKeys.length == 1 && errKeys[0] == 'content' && mdContnet + if (!err || Object.keys(err).length == 0) { + if (this.state.isEdit) { + this.doEdit(courseId, values) + } else { + this.doNew(courseId, values) + } + + } else { + $("html").animate({ scrollTop: $('html').scrollTop() - 100 }) + } + }) + } + doEdit = (courseId, values) => { + let attachment_ids = this.state.contentFileList.map(item => { + return item.response ? item.response.id : item.id + }) + let reference_attachment_ids = this.state.answerFileList.map(item => { + return item.response ? item.response.id : item.id + }) + + const { min_num, max_num, base_on_project, category } = this.state + const isGroup = this.props.isGroup() + + const params = { + type: isGroup ? 3 : 1, + name: values.title, + description: values.description, + reference_answer: values.reference_answer, + attachment_ids, + reference_attachment_ids, + + min_num, + max_num, + base_on_project + } + this.props.doEdit && this.props.doEdit(params) + } + doNew = (courseId, values) => { + let attachment_ids = this.state.contentFileList.map(item => { + return item.response ? item.response.id : item.id + }) + let reference_attachment_ids = this.state.answerFileList.map(item => { + return item.response ? item.response.id : item.id + }) + const isGroup = this.props.isGroup() + const { min_num, max_num, base_on_project, category } = this.state + + const params = { + type: isGroup ? 3 : 1, + name: values.title, + description: values.description, + reference_answer: values.reference_answer, + attachment_ids, + reference_attachment_ids, + + min_num, + max_num, + base_on_project + } + this.props.doNew && this.props.doNew(params) + + } + + handleContentUploadChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let contentFileList = info.fileList; + this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); + } + } + handleAnswerUploadChange = (info) => { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let answerFileList = info.fileList; + this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); + } + } + + onAttachmentRemove = (file, stateName) => { + if(!file.percent || file.percent == 100){ + this.props.confirm({ + content: '是否确认删除?', + + onOk: () => { + this.deleteAttachment(file, stateName) + }, + onCancel() { + console.log('Cancel'); + }, + }); + } + return false; + } + deleteAttachment = (file, stateName) => { + // 初次上传不能直接取uid + const url = `/attachments/${file.response ? file.response.id : file.uid}.json` + axios.delete(url, { + }) + .then((response) => { + if (response.data) { + const { status } = response.data; + if (status == 0) { + console.log('--- success') + + this.setState((state) => { + const index = state[stateName].indexOf(file); + const newFileList = state[stateName].slice(); + newFileList.splice(index, 1); + return { + [stateName]: newFileList, + }; + }); + } + } + }) + .catch(function (error) { + console.log(error); + }); + } + max_num_change = (val) => { + if (val < 2) { + // this.setState({ + // max_num: 2, + // }) + return; + } + const { min_num } = this.state; + this.setState({ + max_num: val, + min_num: val <= min_num ? val - 1 : min_num + }) + } + personNumValidator = (rule, value, callback) => { + const { min_num, max_num } = this.state; + const form = this.props.form; + if (!min_num) { + callback('最小人数不能为空'); + } else if (min_num < 1) { + callback('最小人数不能小于1'); + } else if (!max_num) { + callback('最大人数不能为空'); + } else if (max_num < min_num) { + callback('最大人数不能小于最小人数'); + } else { + callback(); + } + } + min_num_change = (val) => { + this.setState({ min_num: val }) + } + base_on_project_change = () => { + this.setState({ base_on_project: !this.state.base_on_project }) + } + componentDidMount() { + window.$('.groupSetting .ant-form-item-label > label').addClass('ant-form-item-required') + } + + render(){ + let {typeId,coursesId,pageType}=this.props.match.params; + const { getFieldDecorator } = this.props.form; + const isGroup = this.props.isGroup() + let{ + title_value, contentFileList, answerFileList, max_num, min_num, base_on_project, + init_max_num, init_min_num, + title_num, course_name, category, has_commit, has_project, + + isEdit + }=this.state + const { current_user } = this.props + + const courseId = this.state.course_id || this.props.match.params.coursesId ; + + if ((isEdit) && !this.state.workLoaded) { + return '' + } + const uploadProps = { + width: 600, + fileList: contentFileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUrl()}/api/attachments.json`, + onChange: this.handleContentUploadChange, + onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'), + beforeUpload: (file) => { + console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 150; + if (!isLt150M) { + this.props.showNotification('文件大小必须小于150MB!'); + } + return isLt150M; + }, + }; + const answerUploadProps = { + width: 600, + fileList: answerFileList, + multiple: true, + // https://github.com/ant-design/ant-design/issues/15505 + // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 + // showUploadList: false, + action: `${getUrl()}/api/attachments.json`, + onChange: this.handleAnswerUploadChange, + onRemove: (file) => this.onAttachmentRemove(file, 'answerFileList'), + beforeUpload: (file) => { + console.log('beforeUpload', file.name); + const isLt150M = file.size / 1024 / 1024 < 150; + if (!isLt150M) { + this.props.showNotification('文件大小必须小于150MB!'); + } + return isLt150M; + }, + }; + + return( + + + +
              + + {getFieldDecorator('title', { + rules: [{ + required: true, message: '请输入标题' + }], + })( + + )} + + + + + { + {getFieldDecorator('description', { + rules: [{ + required: true, message: '请输入作业内容和要求', + },{ + max: 5000 , message:'最大限制5000个字符' + }], + })( + + )} + } + + + (单个文件150M以内) + + + + { isGroup && + + {getFieldDecorator('personNum', { + validateTrigger: 'onNone', + // rules: [{ + // required: true, + // message: '人数不能为空' + // validator: this.personNumValidator + // required: true, message: '请输入最小人数和最大人数' + // }], + })( +
              +

              + + {/* max={has_commit ? init_min_num : null } */} + + + + ~ + {/* min={has_commit ? init_max_num : (min_num == undefined ? 2 : min_num + 1) } */} + + + + +

              +

              + + 基于项目实施 + + + +

              +
              + )} + +
              + } +
              + + {getFieldDecorator('reference_answer', { + rules: [{ + max: 5000 , message:'最大限制5000个字符' + }], + })( + + )} + + + + (单个文件150M以内) + +
              + +
              + + + + + ) + } +} +const WrappedWorkForm = Form.create({ name: 'NewWorkForm' })(NewWorkForm); +export default WrappedWorkForm; \ No newline at end of file diff --git a/public/react/src/modules/courses/busyWork/common/TabRightComponents.js b/public/react/src/modules/courses/busyWork/common/TabRightComponents.js index 34044330d..25ae55203 100644 --- a/public/react/src/modules/courses/busyWork/common/TabRightComponents.js +++ b/public/react/src/modules/courses/busyWork/common/TabRightComponents.js @@ -63,7 +63,7 @@ class TabRightComponents extends Component{ }) } }else { - this.props.slowDownload(url) + this.props.slowDownload(url); // this.props.showNotification(`正在下载中`); // window.open("/api"+url, '_blank'); } diff --git a/public/react/src/modules/courses/busyWork/commonWork.js b/public/react/src/modules/courses/busyWork/commonWork.js index 584965039..f8042d476 100644 --- a/public/react/src/modules/courses/busyWork/commonWork.js +++ b/public/react/src/modules/courses/busyWork/commonWork.js @@ -76,6 +76,7 @@ class commonWork extends Component{ } componentDidUpdate(prevProps, prevState) { if (prevProps.match.path != this.props.match.path) { + this.clearSelection() this._getList() } } @@ -226,7 +227,7 @@ class commonWork extends Component{ } clearSelection = () => { - this.setState({ checkBoxValues: [] }) + this.setState({ checkBoxValues: [], checkAll: false }) } // onSetPublic = () => { diff --git a/public/react/src/modules/courses/common/CNotificationHOC.js b/public/react/src/modules/courses/common/CNotificationHOC.js index 9a08268b1..a0374f75b 100644 --- a/public/react/src/modules/courses/common/CNotificationHOC.js +++ b/public/react/src/modules/courses/common/CNotificationHOC.js @@ -109,7 +109,7 @@ export function CNotificationHOC(options = {}) { const { title, content,subContent, onOk, onCancel, okText } = object; this.onCancel = onCancel this.onOk = onOk - this.okText = okText || '' + this.okText = okText || '确定' this.setState({ title, content , subContent , dialogOpen: true }) } onDialogOkBtnClick = () => { @@ -146,7 +146,15 @@ export function CNotificationHOC(options = {}) { return ( + 请先选择课堂 :""} -
              + diff --git a/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js b/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js index 850ed2b89..8c365022e 100644 --- a/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js +++ b/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js @@ -1,5 +1,6 @@ + import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -13,6 +14,9 @@ import { import './completetaskdetails.css'; import GroupPackage from "../groupjobbank/GroupPackage"; import GroupPackage2 from "../groupjobbank/GroupPackage2"; +import AttachmentsList from "../../../common/components/attachment/AttachmentList"; +import NoneData from '../../courses/coursesPublic/NoneData' + class Groupjobbandetails extends Component { @@ -57,20 +61,24 @@ class Groupjobbandetails extends Component { render() { - + let{datas}=this.props; return ( -
              +
              -
              + { + datas.description===null||datas.description==="null"||datas.description===""? + "" + : + + } +
              + {datas.attachments === undefined || datas.attachments === null || datas.attachments === ""? "" : + } + +
              - -
              diff --git a/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js b/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js index d7cd7a62c..9cfab4aa5 100644 --- a/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js +++ b/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js @@ -1,34 +1,43 @@ import React, {Component} from "react"; -import {Link, NavLink} from 'react-router-dom'; -import {WordsBtn, ActionBtn} from 'educoder'; +import {BrowserRouter as Router,Route,Switch,Link, NavLin} from 'react-router-dom'; +import {WordsBtn, ActionBtn,getImageUrl} from 'educoder'; +import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Button,Form } from "antd"; import axios from 'axios'; -import { - notification -} from "antd"; -import CoursesListType from '../coursesPublic/CoursesListType'; -import Completetaskdetails from './Completetaskdetails'; +import BanksMenu from '../../user/usersInfo/banks/banksMenu' +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; import '../css/members.css'; import "../common/formCommon.css"; import '../css/Courses.css'; import '../css/busyWork.css'; import '../poll/pollStyle.css'; +const Completetaskdetails = Loadable({ + loader: () => import('./Completetaskdetails'), + loading: Loading, +}) + class Completetaskpage extends Component { //分组作业内容详情 constructor(props) { super(props); // this.answerMdRef = React.createRef(); - this.setState({ + this.state={ workid:1, isSpin:false, datas:[], - }) + visible:false, + banksMenu:undefined + } } componentDidMount() { // console.log("父组件加载框"); + this.getonedata(); + } + getonedata(){ if( this.props.match.params.workid){ this.setState({ workid: this.props.match.params.workid, @@ -47,14 +56,41 @@ class Completetaskpage extends Component { this.setState({ isSpin:true, }) - let url = `/homework_banks/${workids}.json`; + let url = `/task_banks/${workids}.json`; // axios.get(url).then((response) => { if(response){ if(response.data){ this.setState({ - datas:response.data.informs, - }) + datas:response.data, + }); + try { + const crumbData={ + title:response && response.data && response.data.name, + is_public:response && response.data && response.data.is_public, + crumbArray:[ + {content:'详情'} + ] + }; + const menuData={ + tab:'0',//tab选中的index + menuArray:[//tab以及tab路由 + {to:`/banks/gtask/${workids}/${this.props.match.params.type}?tab=0`,content:'内容详情'}, + ], + category:'gtask',//毕设选题 + tos:`/banks/gtask/${workids}/edit/${this.props.match.params.type}?tab=0`, + id:workids, + is_public:response && response.data && response.data.is_public, + type:this.props.match.params.type, + authorize:response && response.data && response.data.authorize, + } + this.setState({ + banksMenu:menuData + }) + this.props.initPublic(crumbData,response.data); + }catch (e) { + + } }else { this.setState({ datas:[], @@ -79,60 +115,35 @@ class Completetaskpage extends Component { }) }); } - - - - bindRef = ref => { this.child = ref } -///////////////教师截止 - render() { - - const isAdmin = this.props.isAdmin(); - // console.log(119) - + let {datas} = this.state; + let{ + banksMenu + }=this.state; return ( -
              - - -
              - -
              -

              - 题库 - > - 详情 -

              -
              -
              -

              - MySQL数据库编程开发实训(基础篇) -

              - -
              - -
              - -
              - - - + +
              + { + banksMenu && + + } + + { + return () + } + }> +
              -
              + ) } } export default Completetaskpage; - diff --git a/public/react/src/modules/courses/completetaskdetails/completetaskdetails.css b/public/react/src/modules/courses/completetaskdetails/completetaskdetails.css index fd1b10f51..2e63bf0ce 100644 --- a/public/react/src/modules/courses/completetaskdetails/completetaskdetails.css +++ b/public/react/src/modules/courses/completetaskdetails/completetaskdetails.css @@ -1,16 +1,18 @@ + .yslquestionbank1{ padding-top: 30px !important; padding-right: 30px !important; padding-left: 30px !important; + min-height: 500px !important; } .yslquesHeigth{ - min-height: 500px !important; + width: 100% !important; + } .yslquesmarkdowntext{ font-size: 16px; color: #707070; - } .yslquesmat26{ margin-top: 26px; @@ -55,4 +57,13 @@ .yslboomdivsys{ color: #666666; font-size: 14px; +} +.pad20{ + padding-bottom: 20px !important; +} +.mt24{ + margin-top: 24px !important ; + } +.pd30{ + margin-bottom: 30px; } \ No newline at end of file diff --git a/public/react/src/modules/courses/comtopicdetails/CompletetopicdePage.js b/public/react/src/modules/courses/comtopicdetails/CompletetopicdePage.js index cde4f5f5e..be1241163 100644 --- a/public/react/src/modules/courses/comtopicdetails/CompletetopicdePage.js +++ b/public/react/src/modules/courses/comtopicdetails/CompletetopicdePage.js @@ -1,29 +1,32 @@ import React, {Component} from "react"; -import {Link, NavLink} from 'react-router-dom'; -import {WordsBtn, ActionBtn} from 'educoder'; +import {BrowserRouter as Router,Route,Switch,Link, NavLin} from 'react-router-dom'; +import {WordsBtn, ActionBtn,getImageUrl} from 'educoder'; import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Button,Form } from "antd"; import axios from 'axios'; -import { - notification -} from "antd"; -import CoursesListType from '../coursesPublic/CoursesListType'; -import Completetopicdetails from './Completetopicdetails'; +import BanksMenu from '../../user/usersInfo/banks/banksMenu' +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; import '../css/members.css'; import "../common/formCommon.css"; import '../css/Courses.css'; import '../css/busyWork.css'; import '../poll/pollStyle.css'; - +const Completetopicdetails = Loadable({ + loader: () => import('./Completetopicdetails'), + loading: Loading, +}) class CompletetopicdePage extends Component { //毕设选题内容详情 constructor(props) { super(props); // this.answerMdRef = React.createRef(); - this.setState({ + this.state={ workid:1, isSpin:false, datas:[], - }) + visible:false, + banksMenu:undefined + } } @@ -48,14 +51,41 @@ class CompletetopicdePage extends Component { this.setState({ isSpin:true, }) - let url = `/homework_banks/${workids}.json`; + let url = `/gtopic_banks/${workids}.json`; // axios.get(url).then((response) => { if(response){ if(response.data){ this.setState({ - datas:response.data.informs, - }) + datas:response.data, + }); + try { + const crumbData={ + title:response && response.data && response.data.name, + is_public:response && response.data && response.data.is_public, + crumbArray:[ + {content:'详情'} + ] + } + const menuData={ + tab:'0',//tab选中的index + menuArray:[//tab以及tab路由 + {to:`/banks/gtopic/${workids}/${this.props.match.params.type}?tab=0`,content:'内容详情'}, + ], + category:'gtopic',//毕设选题 + tos:`/banks/gtopic/${workids}/edit/${this.props.match.params.type}?tab=0`, + id:workids, + is_public:response && response.data && response.data.is_public, + type:this.props.match.params.type, + authorize:response && response.data && response.data.authorize, + } + this.setState({ + banksMenu:menuData + }) + this.props.initPublic(crumbData,response.data); + }catch (e) { + + } }else { this.setState({ datas:[], @@ -81,58 +111,37 @@ class CompletetopicdePage extends Component { }); } - /// 确认是否下载 - - - bindRef = ref => { this.child = ref } -///////////////教师截止 - render() { + let {tab,datas,visible} = this.state; - const isAdmin = this.props.isAdmin(); - // console.log(119) - - + let{ + banksMenu + }=this.state + // + // const common={ + // initPublic:this.initPublic, + // } return ( -
              - - -
              - -
              -

              - 题库 - > - 详情 -

              -
              -
              -

              - MySQL数据库编程开发实训(基础篇) -

              - -
              - -
              - -
              - - - {/*{parseInt(tab) === 1 ? :""}*/} - + +
              + { + banksMenu && + + } + + { + return () + } + }> +
              -
              + ) } } diff --git a/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js b/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js index 15b4c24cf..856c0d630 100644 --- a/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js +++ b/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -12,6 +12,8 @@ import { } from "antd"; import GroupPackage from '../groupjobbank/GroupPackage' import './completetopicde.css'; +import AttachmentsList from "../../../common/components/attachment/AttachmentList"; +import NoneData from '../../courses/coursesPublic/NoneData' class Completetopicdetails extends Component { @@ -56,52 +58,81 @@ class Completetopicdetails extends Component { render() { - + let{datas}=this.props; return (
              - -
              - - + { + datas.description===null? + "" + :datas.description==="null"? + "" + : + datas.description===""? + "" + : + + } + + {datas.attachment_list === undefined ? + (datas.description===undefined || datas.description===null||datas.description===""? + + : + "" + ) + : + datas.attachment_list === null ? + (datas.description===undefined || datas.description===null||datas.description===""? + + : + "" + ) + : + datas.attachment_list.length === 0 ? + (datas.description===undefined || datas.description===null||datas.description===""? + + : + "" + ) + : +
              + +
              + }

              课题类型: - 设计 + {datas&&datas.topic_type===1?"设计":datas&&datas.topic_type===2?"论文":datas&&datas.topic_type===3?"创作":"无"}

              课题来源: - 生产/社会实践 + {datas&&datas.topic_source===1?"生产/社会实际":datas&&datas.topic_source===2?"结合科研":datas&&datas.topic_source===3?"其它":"无"}

              课题性质1: - 设计 + {datas&&datas.topic_property_first===1?"真题":datas&&datas.topic_property_first===2?"模拟题":"无"}

              课题性质2: - 设计 + {datas&&datas.topic_property_second===1?"纵向课题":datas&&datas.topic_property_second===2?"横向课题":datas&&datas.topic_property_second===3?"自选":"无"}

              -
              +

              课题重复情况: - 新需求 + {datas&&datas.topic_repeat===1?"新题":datas&&datas.topic_repeat===2?"往届题,有新要求":datas&&datas.topic_repeat===3?"往届题,无新要求":"无"}

              调研或实习地点: - 长沙 + {datas&&datas.province}{datas&&datas.city}

              课题单位来源: - 湖南省据C++创始人Stroustrup有限公司 + {datas&&datas.source_unit===undefined?"无":datas&&datas.source_unit===null?"无":datas&&datas.source_unit===""?"无":datas&&datas.source_unit==="null"?"无":datas.source_unit}

              diff --git a/public/react/src/modules/courses/comtopicdetails/completetopicde.css b/public/react/src/modules/courses/comtopicdetails/completetopicde.css index fd566ffdc..19367b3af 100644 --- a/public/react/src/modules/courses/comtopicdetails/completetopicde.css +++ b/public/react/src/modules/courses/comtopicdetails/completetopicde.css @@ -2,10 +2,10 @@ padding-top: 30px !important; padding-right: 30px !important; padding-left: 30px !important; + min-height: 500px !important; } .yslquesHeigth{ - min-height: 500px !important; - + width: 100% !important; } .yslquesmarkdowntext{ font-size: 16px; @@ -55,4 +55,11 @@ .yslboomdivsys{ color: #666666; font-size: 14px; +} +.mb29px{ + padding-top: 14px !important; + margin-bottom: 29px !important; +} +.pd30{ + margin-bottom: 30px; } \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesDetail/CoursesBanner.js b/public/react/src/modules/courses/coursesDetail/CoursesBanner.js index 15f57f130..21ac26727 100644 --- a/public/react/src/modules/courses/coursesDetail/CoursesBanner.js +++ b/public/react/src/modules/courses/coursesDetail/CoursesBanner.js @@ -655,7 +655,10 @@ class CoursesBanner extends Component { this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/teachers")} className={"pointer"}> 教师 {coursedata.teacher_count} - this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/students")} className={"pointer"}> + this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/students"):"":()=>this.setHistoryFun("/courses/"+this.props.match.params.coursesId+"/students")} + > 学生 {coursedata.student_count} {coursedata.credit===null?"": diff --git a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js index 24235d723..35b06f305 100644 --- a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js +++ b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js @@ -6,6 +6,7 @@ import { DragDropContext,Draggable, Droppable} from 'react-beautiful-dnd'; import Modals from '../../modals/Modals'; import { on, off, trigger } from 'educoder'; import './MainLeftNav.css'; +import MyEduChapterupdate from './MyEduChapterupdate'; const CheckboxGroup = Checkbox.Group; @@ -57,7 +58,8 @@ class Coursesleftnav extends Component{ toopvisible:false, toopvisibleindex:undefined, sandiantypes:undefined, - antIcon:false + antIcon:false, + chapterupdate:false, } } @@ -755,7 +757,15 @@ class Coursesleftnav extends Component{ {/*分班*/} {/*{item.type==="course_group"? :""}*/}
              this.Navmodalnames(e,3,"editname",item.id,item.name)}>重命名
              - + {/*online_learning*/} + {/*{*/} + {/* this.props.isClassManagement()===true?*/} + {/* (*/} + {/* item.type==="online_learning"?*/} + {/*
              this.Chapterediting(e,item.id,item.url)}>章节编辑
              */} + {/* :""*/} + {/* )*/} + {/* :""}*/}
              this.edithidden(e,item.id)}>隐藏
              this.editSetup(e,item.id)}>置顶
              ) @@ -773,10 +783,25 @@ class Coursesleftnav extends Component{ {item.type==="board"?
              this.Navmodalnames(e,7,"editSecondname",iem.category_id,iem.category_name)}>重命名
              :""} {item.type==="board"?
              this.deleteSecondary(e,3,iem.category_id,item.category_url)}>删除
              :""}
              ) - } - - + }; + //章节编辑 + Chapterediting=(e,id,url)=> { + e.stopPropagation();//阻止冒泡 + console.log(url); + console.log(id); + //页面刷新 + this.setState({ + chapterupdate:true, + }) + // this.props.history.replace( url ); + // this.props.comyslElearning(true); + }; + setchapterupdatefalse =()=>{ + this.setState({ + chapterupdate:false, + }) + } render(){ let { twosandiantype, @@ -815,6 +840,27 @@ class Coursesleftnav extends Component{ > + {/*{*/} + {/* this.state.chapterupdate===true?*/} + {/*
              */} + {/* */} + {/* */} + {/* */} + {/*
              */} + {/* :*/} + {/* ""*/} + {/*}*/} { Navmodalnametype===true? + + + {this.renderTreeNodes(treeData)} + + +
              +
              +
              +
              this.onChange(e)} checked={this.state.myeduchecked}>
              +
              已选择3 个章节 5个实训
              +
              勾选则在课堂中显示,否则不显示
              +
              + + + ) + } +} + +export default MyEduChapterupdate; \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesDetail/chapterupdate.css b/public/react/src/modules/courses/coursesDetail/chapterupdate.css new file mode 100644 index 000000000..252bf334b --- /dev/null +++ b/public/react/src/modules/courses/coursesDetail/chapterupdate.css @@ -0,0 +1,34 @@ +.yslcheckbox{ + display: flex; + flex-direction: row; + } +.yslcheckbox2{ + display: flex; + flex-direction: row-reverse; + +} +.heigth459px{ + max-height:459px; +} +.private-listtwo{ + overflow-y: auto; + overflow-x: hidden; +} +/*滚动条*/ +.private-listtwo::-webkit-scrollbar { + width: 8px; + height: 8px; +} + + +.private-listtwo::-webkit-scrollbar-thumb { + background-color: #E3EBF4; + box-shadow: 0px 0px black; +} + + +.private-listtwo::-webkit-scrollbar-track { + border-radius:3px; + -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0); + background-color: white; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js b/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js index a15cb0617..1f5dea3e8 100644 --- a/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js +++ b/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js @@ -34,12 +34,15 @@ class AccessoryModal2 extends Component{ } // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - console.log(fileList) - // for(var list of fileList ){ - // console.log(fileList) - // } - this.setState({ fileList }); + if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed'){ + let fileList = info.fileList; + console.log(fileList) + // for(var list of fileList ){ + // console.log(fileList) + // } + this.setState({ fileList }); + } + } onAttachmentRemove = (file) => { diff --git a/public/react/src/modules/courses/coursesPublic/AppraiseModal.js b/public/react/src/modules/courses/coursesPublic/AppraiseModal.js new file mode 100644 index 000000000..120e57b2b --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/AppraiseModal.js @@ -0,0 +1,192 @@ +import React,{ Component } from "react"; +import { Modal,Checkbox,Upload,Button,Icon,message,Input,Radio} from "antd"; +import { WordNumberTextarea } from 'educoder'; +import axios from 'axios'; + +class AppraiseModal extends Component{ + constructor(props){ + super(props); + this.state={ + group_ids:[], + fileList:[], + Inputsval:undefined, + textareavaltype:false, + comment:undefined, + hidden_comment:undefined + } + } + + componentDidMount() { + let{data,work_comment,work_comment_hidden}=this.props; + + if(this.props.showAppraisetype==="child"){ + data.stage_list.map((item,key)=>{ + if(this.props.challenge_id===item.challenge_id){ + this.setState({ + comment:item.challenge_comment, + hidden_comment:item.challenge_comment_hidden, + }) + } + }) + }else{ + this.setState({ + comment:work_comment, + hidden_comment:work_comment_hidden, + }) + } + + } + + comment=(e)=>{ + this.setState({ + comment:e.target.value + }) + } + + hidden_comment=(e)=>{ + this.setState({ + hidden_comment:e.target.value + }) + } + Saves=()=>{ + let{comment,hidden_comment}=this.state; + let commenttype=comment===undefined||comment===null||comment===""; + let hidden_commenttype=hidden_comment===undefined||hidden_comment===null||hidden_comment===""; + + if(commenttype===true&&hidden_commenttype===true){ + this.setState({ + textareavaltype:true + }) + return + } + + //comment 是 text 可见的评阅内容 + // hidden_comment 是 text 不可见的评阅内容 + // challenge_id 否 int 关卡id(关卡评阅才需传关卡id) + let challenge_id=this.props.showAppraisetype==="child"?this.props.challenge_id:undefined + + let url=`/student_works/${this.props.match.params.homeworkid}/shixun_work_comment.json` + axios.post(url, { + comment:comment, + hidden_comment:hidden_comment, + challenge_id:challenge_id + }).then((response) => { + if(response.data.status===0){ + this.props.showCancel(comment,hidden_comment,challenge_id,response.data.comment_id) + this.props.showNotification(response.data.message) + }else{ + this.props.showNotification(response.data.message) + } + }).catch((error) => { + console.log(error) + }); + } + + render(){ + let {textareavaltype,comment,hidden_comment}=this.state; + return( +
              + + + + +
              + +
              +

              + 可见:(学生可查看老师的评阅内容) +

              + {/**/} + {/*可见 (学生查看老师的评阅内容)*/} + {/*不可见 (仅对课堂老师可见)*/} + {/**/} + this.comment(e)} + value={comment} + maxlength={500} + /> + +

              + 不可见:(仅对课堂老师可见) +

              + this.hidden_comment(e)} + value={hidden_comment} + maxlength={500} + /> + +
            • 评阅内容至少有一个不为空
            • +
              + + +
              +
              +
              + ) + } +} +export default AppraiseModal; \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js b/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js index 3538aaf57..4510a7080 100644 --- a/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js +++ b/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js @@ -139,7 +139,7 @@ function create_editorMD(id, width, high, placeholder, imageUrl, callback, initV }); $("#" + _id + " [type=\"inline\"]").bind("click", function () { - _editorName.cm.replaceSelection("$$$$"); + _editorName.cm.replaceSelection("`$$$$`"); var __Cursor = _editorName.cm.getDoc().getCursor(); _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); _editorName.cm.focus(); diff --git a/public/react/src/modules/courses/coursesPublic/NewShixunModel.js b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js new file mode 100644 index 000000000..fbb97cbb5 --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js @@ -0,0 +1,555 @@ +import React,{Component} from 'react'; +import { Modal,Checkbox,Select,Input,Tooltip,Spin,Icon,Drawer,Dropdown,Menu,Breadcrumb,Pagination,Button,notification} from "antd"; +import axios from'axios'; +import NoneData from "../coursesPublic/NoneData"; +import './Newshixunmodel.css'; +const Search = Input.Search; +class NewShixunModel extends Component{ + constructor(props){ + super(props) + this.state={ + shixun_list:undefined, + shixuns_count:undefined, + Grouplist:[], + allGrouplist:[{page:1,list:[]}], + page:1, + type:'all', + status:'all', + keyword:undefined, + order:'desc', + diff:0, + limit:15, + } + } + componentDidMount() { + let{page,type,keyword,order,diff,limit,status}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + getdatalist=(page,type,newstatus,keyword,order,diff,limit,pagetype)=>{ + this.setState({ + isspinning:true + }) + let status=this.props.statustype===undefined?newstatus:'published'; + let url="/shixun_lists.json" + axios.get(url,{params:{ + page, + type, + status, + keyword, + order, + diff, + limit + }}).then((response) => { + if(response.data){ + if(pagetype===undefined){ + this.setState({ + shixun_list:response.data.shixun_list, + shixuns_count:response.data.shixuns_count, + Grouplist:[], + isspinning:false + }) + }else if(pagetype==="pagetype"){ + this.setState({ + shixun_list:response.data.shixun_list, + shixuns_count:response.data.shixuns_count, + isspinning:false + }) + } + + } + }).catch((error) => { + this.setState({ + isspinning:false + }) + }) + } + + DropdownClick=(diff)=>{ + this.setState({ + diff:diff + }) + let{page,type,status,keyword,order,limit}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + ItsCourse=(item)=>{ + return + {item.map((list,key)=>{ + return( + + {list.name} + + ) + })} + + } + + getGrouplist=(Grouplist)=>{ + let {page,allGrouplist}=this.state; + let newallGrouplist=allGrouplist; + var a=newallGrouplist.find((value,index,arr)=>{ + return value.page==page + }); + + if(a!=undefined){ + newallGrouplist.map((item,key)=>{ + if(item.page===page){ + item.list=Grouplist + } + }) + } + + + let newGrouplist=[]; + + newallGrouplist.map((item,key)=>{ + item.list.map((items,ke)=>{ + newGrouplist.push(items) + }) + }) + + + this.setState({ + Grouplist: newGrouplist, + allGrouplist:newallGrouplist + }) + } + + PaginationCourse=(pageNumber)=>{ + let {allGrouplist}=this.state; + let newallGrouplist=allGrouplist; + var v=newallGrouplist.find((value,index,arr)=>{ + return value.page==pageNumber + }); + + if(v===undefined){ + newallGrouplist.push({page:pageNumber,list:[]}) + } + + let{type,status,keyword,order,diff,limit}=this.state; + this.getdatalist(pageNumber,type,status,keyword,order,diff,limit,"pagetype") + this.setState({ + page:pageNumber, + allGrouplist:newallGrouplist + }) + + } + + belongto=(value)=>{ + this.setState({ + type:value, + keyword:undefined, + page:1 + }) + let{status,order,diff,limit}=this.state; + this.getdatalist(1,value,status,undefined,order,diff,limit) + } + + updatedlist=(order)=>{ + + if(order==="desc"){ + this.setState({ + order:"asc" + }) + let{type,page,status,keyword,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,"asc",diff,limit) + }else{ + this.setState({ + order:"desc" + }) + let{type,page,status,keyword,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,"desc",diff,limit) + } + + } + + setdatafunsval=(e)=>{ + this.setState({ + keyword:e.target.value + }) + } + + setdatafuns=(value)=>{ + + this.setState({ + keyword:value, + type:undefined, + page:1, + status:'all', + order:'desc', + diff:0, + limit:15, + }) + this.getdatalist(1,undefined,'all',value,'desc',0,15) + } + + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } + savecouseShixunModal=()=>{ + + this.setState({ + hometypepvisible:true + }) + let {coursesId}=this.props; + let{Grouplist}=this.state; + if(Grouplist.length===0){ + this.setState({ + hometypepvisible:false + }) + this.showNotification("请先选择实训") + return + } + + if (this.props.chooseShixun) { + if(Grouplist.length>1){ + this.setState({ + hometypepvisible:false + }) + this.showNotification("试卷选择的实训数不能大于1") + return + } + this.props.chooseShixun(Grouplist) + this.setState({ + hometypepvisible:false + }) + return; + } + + if (this.props.pathShixun) { + this.setState({ + hometypepvisible:false + }) + this.props.pathShixun(Grouplist) + return; + } + let url="/courses/"+coursesId+"/homework_commons/create_shixun_homework.json"; + axios.post(url, { + category_id:this.props.category_id===null||this.props.category_id===undefined?undefined:parseInt(this.props.category_id), + shixun_ids:Grouplist, + } + ).then((response) => { + if(response.data.status===-1){ + // this.props.showNotification(response.data.message) + + }else{ + // this.props.courseshomeworkstart(response.data.category_id,response.data.homework_ids) + this.showNotification("操作成功") + this.props.homeworkupdatalists(this.props.Coursename,this.props.page,this.props.order); + this.props.hideNewShixunModelType() + + } + this.setState({ + hometypepvisible:false + }) + // category_id: 3 + // homework_ids: (5) [9171, 9172, 9173, 9174, 9175] + }).catch((error) => { + console.log(error) + this.setState({ + hometypepvisible:false + }) + }) + } + + poststatus=(status)=>{ + this.setState({ + status:status + }) + let{page,type,keyword,order,diff,limit}=this.state; + this.getdatalist(page,type,status,keyword,order,diff,limit) + } + + render() { + + let {diff,Grouplist,status,shixun_list,shixuns_count,page,type,order}=this.state; + // let {visible,patheditarry}=this.props; + // console.log(Grouplist) + // console.log(allGrouplist) + const statusmenus=( + + + this.poststatus("all")}> + 所有 + + + + + this.poststatus("published")} > + 已发布 + + + + + this.poststatus("unpublished")}> + 未发布 + + + + + ); + const menus = ( + + + this.DropdownClick(0)}> + 所有 + + + + + this.DropdownClick(1)} > + 初级 + + + + + this.DropdownClick(2)}> + 中级 + + + + + this.DropdownClick(3)}> + 高级 + + + + + this.DropdownClick(4)}> + 顶级 + + + + ); + + + + return( + +
              + + + + +
              + +
              + +
              +
              + 搜索} + onInput={(e)=>this.setdatafunsval(e)} + onSearch={ (value)=>this.setdatafuns(value)} /> +
              + +
              + +
              + + 已选 {Grouplist.length} 个实训 + {shixuns_count===undefined?"":shixuns_count} 个实训 + + + this.updatedlist(order)}>学习人数 + + + + + + + {this.props.statustype===undefined? + + {status==='all'?"发布状态":status==='published'?"已发布":status==="unpublished"?"未发布":""} + + :""} + + + + {diff===0?"难度":diff===1?"初级":diff===2?"中级":diff===3?"高级":diff===4?"顶级":""} + + +
              + +
              + this.props.hideNewShixunModelType()}>返回 + this.belongto("mine")}>我的实训 + this.belongto("all")}>全部实训 +
              + +
              + + + + {shixun_list===undefined?"":shixun_list.length===0?"":shixun_list.map((item,key)=>{ + + return( +
              +
              +
              +
              + + + + +
              + + {JSON.stringify(item.description) == "{}"?"":
              +
              } + + {item.challenge_names.length===0?"":
              + {item.challenge_names.map((item,key)=>{ + return( + 第{key+1}关:{item} + ) + })} +
              } + +
              +
              +
              + +
              + + + {item.author_name} + {item.author_school_name} + 难度系数:{item.level} + 学习人数:{item.study_count} + + +
              + {item.subjects.length===0?"":this.ItsCourse(item.subjects)}> + + 所属课程 + + } + +
              +
              +
              +
              + )}) + } +
              + + {shixun_list===undefined||shixuns_count===undefined?"":shixun_list.length===0||shixuns_count===0?"":shixuns_count>15?
              + +
              :""} + { + shixun_list===undefined? +
              + +
              + :shixun_list.length===0? :"" + } + + { + shixun_list===undefined?"":shixun_list.length===0?"":
              + + +
              } + +
              + +
              +
              +
              +
              + + ) + } +} + +export default NewShixunModel; + + +// {JSON.stringify(item.content) == "{}"?
              +//
              :
              +// {item.content.description === undefined || item.content.description===0?"":item.content.description.map((item,key)=>{ +// return( +// {} +// ) +// })} +//
              } +// +// {JSON.stringify(item.content) == "{}"?item.challenge_names.length===0?"":
              +// {item.challenge_names.map((item,key)=>{ +// return( +// 第{key+1}关:{item} +// ) +// })} +//
              :
              +// {item.content.challenge_names === undefined || item.content.challenge_names===0?"":item.content.challenge_names.map((item,key)=>{ +// return( +// {} +// ) +// })} +//
              } \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css b/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css new file mode 100644 index 000000000..2e8abce53 --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css @@ -0,0 +1,250 @@ +.searchinput{ + width: 800px; + margin-top: 53px; +} +.newshixunheadersear{ + display: flex; + justify-content: center; +} +.packinput .ant-input{ + height: 55px; + width:663px !important; + font-size: 14px; + /*color: #681616 !important;*/ + border-color: #E1EDF8 !important; + padding-left: 20px; +} + +.packinput .ant-input-group-addon .ant-btn{ + width:137px !important; + font-size: 18px; + height: 53px; + background:rgba(76,172,255,1); + +} +.tabtitle{ + height: 62px !important; + box-shadow: 3px 10px 21px 0px rgba(76, 76, 76, 0.15); + border-radius: 6px; + background: #fff; + display: flex; + justify-content: center; +} +.tabtitles2{ + background: #fff; + height: 62px !important; + width: 1200px; +} + +.tabtitless{ + height: 62px !important; + line-height: 62px !important; + +} +.tabtitle1{ + +} +.tabtitle2{ + margin-left: 30px !important; + +} + + +.counttit{ + display: flex; + justify-content: center; +} + +.counttittext{ + text-align: left; + width: 1200px; + height: 18px; + color: #888888; + font-size: 13px; + margin-top: 24px; + + +} +.counttittexts{ + color: #4CACFF !important; + font-size: 13px; +} + +.mainx{ + display: flex; + justify-content: center; + margin-top: 17px; +} +.project-packages-list{ + +} +.project-package-item{ + display: -webkit-flex; + display: flex; + flex-direction:column; + margin-bottom: 20px; + padding: 20px; + background: white; + /* box-shadow: 1px 3px 3px 1px rgba(156,156,156,0.16); */ + +} +.xuxianpro{ + height: 20px; + border-bottom: 1px dashed; + border-color: #EAEAEA; + margin-bottom: 18px; +} +.magr11{ + margin-top: 11px; +} +.highlight{ + color: #4CACFF; +} +.fonttext{ + font-size: 20px; + font-weight:bold; +} + +.fontextcolor{ + color: #777777; +} +.tzbq{ + margin-left: 68px; +} +.tzbqx{ + /* margin-left: 24px; */ +} +.bjyss{ + background: #F8F8F8; +} +.zj{ + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap +} +.ziticor{ + color: #777777; + font-size: 13px; +} +.foohter{ + margin-top: 20px; + display: flex; + flex-direction:row; +} + +.maxwidth1100{ + max-width: 1100px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + font-size: 18px !important; + font-weight: 500; + color: rgba(51,51,51,1) !important; +} + + +.newshixunmodelmidfont{ + font-size: 14px; + font-weight: 400; + color: #999999; + margin-top: 15px; + margin-left: 30px; + max-width: 1100px; + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; +} + +.newshixunmodelbotfont{ + font-size:12px; + font-weight:400; + color:rgba(102,102,102,1); + margin-top: 15px; + margin-left: 30px; +} + +.newshixunlist{ + max-height:227px; + width: 1200px; +} + +.xuxianpro { + height: 20px; + border-bottom: 1px dashed; + border-color: #eaeaea; + margin-bottom: 18px; +} + +.newshixunpd030{ + padding: 0px 30px; +} + +.pd303010{ + padding: 30px 30px 10px; +} + +.newshixunfont12{ + font-size: 12px; + color: rgba(76,172,255,1); + line-height: 21px; +} + +.newshixunmode{ + width: 100px; + height: 38px; + border-radius: 3px; + border: 1px solid rgba(191,191,191,1); +} + +.ntopsj { + position: absolute; + top: -4px; +} + +.nyslbottomsj { + position: absolute; + bottom: -6px; +} + +.inherits .ant-dropdown-menu-item{ + cursor: inherit !important; +} + +.menus{ + width: 91px; + text-align: center; +} + +.newshixunmodelbotfont span{ + display: inline-block; + margin-right: 34px; +} + +.minhegiht300{ + min-height: 300px; +} + +.newshixunlist:hover{ + box-shadow: 1px 6px 16px rgba(156,156,156,0.16); + opacity: 1; + border-radius: 2px; +} + +.newshixun500{ + max-width: 500px; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mt3 { + margin-top: 3px !important; +} + +.highlight{ + color: #4CACFF; +} + diff --git a/public/react/src/modules/courses/coursesPublic/SelectSetting.js b/public/react/src/modules/courses/coursesPublic/SelectSetting.js index 1a18513e7..37b22c205 100644 --- a/public/react/src/modules/courses/coursesPublic/SelectSetting.js +++ b/public/react/src/modules/courses/coursesPublic/SelectSetting.js @@ -253,19 +253,19 @@ class Selectsetting extends Component{ // 附件相关 START handleChange = (info) => { - - let fileList = info.fileList; - if(info.file.status!="removed"){ - this.setState({ - fileList: appendFileSizeToUploadFileAll(fileList), - fileListtype:true - }); - }else{ - this.setState({ - fileList: appendFileSizeToUploadFileAll(fileList), - }); + if(info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + if (info.file.status != "removed") { + this.setState({ + fileList: appendFileSizeToUploadFileAll(fileList), + fileListtype: true + }); + } else { + this.setState({ + fileList: appendFileSizeToUploadFileAll(fileList), + }); + } } - } // onAttachmentRemove = (file) => { diff --git a/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js b/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js index 68a4c6efe..f4f00e5e0 100644 --- a/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js +++ b/public/react/src/modules/courses/coursesPublic/ShixunChooseModal.js @@ -1,120 +1,122 @@ -import React,{ Component } from "react"; -import { Modal,Checkbox,Select,Input,Tooltip} from "antd"; -import axios from'axios'; -import ShixunModal from './ShixunModal' - -const Option = Select.Option; -const Search = Input.Search; -class ShixunChooseModal extends Component{ - constructor(props){ - super(props); - this.state={ - shixunmodal: false, - hometypepvisible: false, - } - } - setVisible = (visible) => { - if (visible) { - this.createCommonWork() - } else { - this.setState({ shixunmodal: visible }) - } - } - hidecouseShixunModal = () => { - this.setVisible(false) - } - componentDidMount() { - - - } - funshixunmodallist=(search,type,loading,page)=>{ - let{newshixunmodallist}=this.state; - let newshixunmodallists=[] - if(page>1){ - newshixunmodallists=newshixunmodallist; - } - this.setState({ - hometypepvisible:loading - }) - let coursesId=this.props.match.params.coursesId; - let url ="/courses/"+coursesId+"/homework_commons/shixuns.json"; - - axios.get(url, { - params: { - search: search, - type:type, - page:page - } - }).then((result)=>{ - if(result.status===200){ - - let shixun_list=result.data.shixun_list; - for(var i=0; i{ - console.log(error); - }) - } - funpatheditarry=(list)=>{ - this.setState({ - patheditarry:list - }) - } - createCommonWork=()=>{ - - this.setState({ - hometypepvisible:true, - patheditarry:[] - }) - - let coursesId=this.props.match.params.coursesId; - let url ="/courses/"+coursesId+"/homework_commons/shixuns.json"; - - axios.get(url).then((result)=>{ - if(result.status===200){ - this.setState({ - shixunmodal:true, - shixunmodallist:result.data, - hometypepvisible:false, - newshixunmodallist:result.data.shixun_list, - }) - } - }).catch((error)=>{ - console.log(error); - }) - } - render(){ - let {Searchvalue,type,category_id, datas, shixunmodal, shixunmodallist - , hometypepvisible, newshixunmodallist, patheditarry }=this.state; - let {visible}=this.props; - - // console.log(patheditarry) - return( - this.funshixunmodallist(search,type,loading,page)} - hometypepvisible={hometypepvisible} - hidecouseShixunModal={this.hidecouseShixunModal} - newshixunmodallist={newshixunmodallist} - coursesId={this.props.match.params.coursesId} - courseshomeworkstart={(category_id,homework_ids)=> this.props.newhomeworkstart - && this.props.newhomeworkstart(category_id,homework_ids)} - funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} - patheditarry={patheditarry} - {...this.props} - > - ) - } -} +import React,{ Component } from "react"; +import { Modal,Checkbox,Select,Input,Tooltip} from "antd"; +import axios from'axios'; +import NewShixunModel from '../coursesPublic/NewShixunModel'; + +const Option = Select.Option; +const Search = Input.Search; +class ShixunChooseModal extends Component{ + constructor(props){ + super(props); + this.state={ + shixunmodal: false, + hometypepvisible: false, + } + } + setVisible = (visible) => { + // if (visible) { + // this.createCommonWork() + // } else { + // + // } + this.setState({ shixunmodal: visible }) + } + hidecouseShixunModal = () => { + this.setVisible(false) + } + componentDidMount() { + + + } + funshixunmodallist=(search,type,loading,page)=>{ + let{newshixunmodallist}=this.state; + let newshixunmodallists=[] + if(page>1){ + newshixunmodallists=newshixunmodallist; + } + this.setState({ + hometypepvisible:loading + }) + let coursesId=this.props.match.params.coursesId; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; + + axios.get(url, { + params: { + search: search, + type:type, + page:page + } + }).then((result)=>{ + if(result.status===200){ + + let shixun_list=result.data.shixun_list; + for(var i=0; i{ + console.log(error); + }) + } + funpatheditarry=(list)=>{ + this.setState({ + patheditarry:list + }) + } + createCommonWork=()=>{ + + this.setState({ + hometypepvisible:true, + patheditarry:[] + }) + + let coursesId=this.props.match.params.coursesId; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; + + axios.get(url).then((result)=>{ + if(result.status===200){ + this.setState({ + shixunmodal:true, + shixunmodallist:result.data, + hometypepvisible:false, + newshixunmodallist:result.data.shixun_list, + }) + } + }).catch((error)=>{ + console.log(error); + }) + } + render(){ + let {Searchvalue,type,category_id, datas, shixunmodal, shixunmodallist + , hometypepvisible, newshixunmodallist, patheditarry }=this.state; + let {visible}=this.props; + + // console.log(patheditarry) + return( + shixunmodal===true?this.funshixunmodallist(search,type,loading,page)} + hometypepvisible={hometypepvisible} + hideNewShixunModelType={this.hidecouseShixunModal} + newshixunmodallist={newshixunmodallist} + coursesId={this.props.match.params.coursesId} + courseshomeworkstart={(category_id,homework_ids)=> this.props.newhomeworkstart + && this.props.newhomeworkstart(category_id,homework_ids)} + funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} + patheditarry={patheditarry} + {...this.props} + >:"" + ) + } +} export default ShixunChooseModal; \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/ShixunModal.js b/public/react/src/modules/courses/coursesPublic/ShixunModal.js index 3a3e20041..5c1720ace 100644 --- a/public/react/src/modules/courses/coursesPublic/ShixunModal.js +++ b/public/react/src/modules/courses/coursesPublic/ShixunModal.js @@ -25,7 +25,7 @@ class ShixunModal extends Component{ hometypepvisible:true, }) let coursesId=this.props.match.params.coursesId; - let url ="/courses/"+coursesId+"/homework_commons/shixuns.json"; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; axios.get(url).then((result)=>{ if(result.status===200){ @@ -51,7 +51,7 @@ class ShixunModal extends Component{ hometypepvisible:loading }) let coursesId=this.props.match.params.coursesId; - let url ="/courses/"+coursesId+"/homework_commons/shixuns.json"; + let url = this.props.shixunsUrl || "/courses/"+coursesId+"/homework_commons/shixuns.json"; axios.get(url, { params: { diff --git a/public/react/src/modules/courses/coursesPublic/Showoldfiles.js b/public/react/src/modules/courses/coursesPublic/Showoldfiles.js index 693e3448b..cb054964e 100644 --- a/public/react/src/modules/courses/coursesPublic/Showoldfiles.js +++ b/public/react/src/modules/courses/coursesPublic/Showoldfiles.js @@ -178,7 +178,7 @@ class Showoldfiles extends Component{
            • - {allfiles.title} + {allfiles.title} {/*{allfiles.is_pdf===false?*/} {/*{allfiles.title}:*/} {/*this.showfiless(allfiles.url)} >{allfiles.title}*/} @@ -198,7 +198,7 @@ class Showoldfiles extends Component{
            • - {item.title} + {item.title} {/*{item.is_pdf===false?*/} {/*{item.title}:*/} {/*this.showfiless(item.url)} >{item.title}*/} diff --git a/public/react/src/modules/courses/coursesPublic/sendResource.js b/public/react/src/modules/courses/coursesPublic/sendResource.js index a9ceb6405..fbc2ebeb2 100644 --- a/public/react/src/modules/courses/coursesPublic/sendResource.js +++ b/public/react/src/modules/courses/coursesPublic/sendResource.js @@ -86,17 +86,18 @@ class Sendresource extends Component{ } // 附件相关 START handleChange = (info) => { - - let fileList = info.fileList; - if(info.file.status!="removed"){ - this.setState({ - fileList: appendFileSizeToUploadFileAll(fileList), - fileListtype:true - }); - }else{ - this.setState({ - fileList: appendFileSizeToUploadFileAll(fileList), - }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + if (info.file.status != "removed") { + this.setState({ + fileList: appendFileSizeToUploadFileAll(fileList), + fileListtype: true + }); + } else { + this.setState({ + fileList: appendFileSizeToUploadFileAll(fileList), + }); + } } } diff --git a/public/react/src/modules/courses/css/Courses.css b/public/react/src/modules/courses/css/Courses.css index 74637571f..305c9f5f1 100644 --- a/public/react/src/modules/courses/css/Courses.css +++ b/public/react/src/modules/courses/css/Courses.css @@ -14,9 +14,6 @@ i.iconfont { } /* BASICS */ -.editormd-preview ol li { - list-style-type: decimal ; -} .CodeMirror { /* Set height, width, borders, and global font properties here */ font-family: monospace; @@ -848,7 +845,7 @@ a.white-btn.use_scope-btn:hover{ font-family: MicrosoftYaHei; font-weight: 400; color: rgba(51,51,51,1); - cursor: pointer; + /*cursor: pointer;*/ max-width: 825px; overflow: hidden; text-overflow: ellipsis; @@ -1220,6 +1217,28 @@ samp { color: #FE4F4C; } + /* 毕设任务 */ + .graduationTaskMenu>a{ + display: block; + position: relative; + line-height: 72px; + font-size: 16px; + margin-right: 30px; + float: left; + } + .graduationTaskMenu>a.active:after{ + position: absolute; + left: 0px; + height: 2px; + width: 100%; + content: ''; + background: #4CACFF; + bottom: 0px; + font-weight:400; + } + .graduationTaskMenu>a.active{ + color: #4CACFF!important; + } /* end */ /* form表单,包含多个item时 */ @@ -1634,8 +1653,9 @@ input.ant-input-number-input:focus { } /* md代码类样式渲染 */ -.markdown-body li{ list-style-type: disc!important;margin-bottom: 0!important; } -.markdown-body ol li{ list-style-type: decimal!important; } +.new_li .markdown-body ul > li{ list-style-type: disc!important;margin-bottom: 0!important; } +.new_li .markdown-body ol > li{ list-style-type: decimal!important; } +.new_li li{ margin-bottom: 0!important; } /* 有不少问题,没有出现'数据已于 09:24:53 保存'时靠太近,和红字提示重叠 */ .upload_under_markdown_editor { diff --git a/public/react/src/modules/courses/elearning/Elearning.js b/public/react/src/modules/courses/elearning/Elearning.js index 2be9bd022..2ed4bbaa8 100644 --- a/public/react/src/modules/courses/elearning/Elearning.js +++ b/public/react/src/modules/courses/elearning/Elearning.js @@ -28,29 +28,38 @@ class Elearning extends Component{ isSpins:false, userlogin:"", isRender:false, + subject_id:0, + myupdataleftNavs:this.myupdataleftNav } } componentDidMount() { // 记得删除退出课堂 - console.log("获取到数据"); - console.log(this.props); + // console.log("在线学习"); + // console.log("获取到数据"); + // console.log(this.props); + this.getdata(); + } + + getdata=()=>{ + console.log("更新了数据了"); let url = `/courses/${this.props.match.params.coursesId}/online_learning.json`; // // axios.get(url).then((response) => { if(response){ if(response.data){ - console.log("获取到到数据"); - console.log(response); - this.setState({ - description: response.data.description, - start_learning:response.data.start_learning, - learned:response.data.learned, - last_shixun:response.data.last_shixun, - stages:response.data.stages, - - }); - } + // console.log("获取到到数据"); + // console.log(response); + this.setState({ + description: response.data.description, + start_learning:response.data.start_learning, + learned:response.data.learned, + last_shixun:response.data.last_shixun, + stages:response.data.stages, + subject_id:response.data.subject_id, + + }); + } } this.setState({ isSpin:false, @@ -71,13 +80,11 @@ class Elearning extends Component{ console.log("12312312312") console.log(e); } - - } componentDidUpdate = (prevProps) => { - console.log("componentDidUpdate"); - console.log(prevProps); - console.log(this.props); + console.log("componentDidUpdate"); + // console.log(prevProps); + // console.log(this.props); if(prevProps.current_user!=this.props.current_user){ if(this.props.current_user!==undefined){ // console.log(this.props.current_user.login); @@ -87,6 +94,17 @@ class Elearning extends Component{ }) } } + + if(prevProps.yslElearning===this.props.yslElearning) { + if(prevProps.yslElearning===true && this.props.yslElearning===true){ + // console.log("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); + // console.log(prevProps.yslElearning); + // console.log(this.props.yslElearning); + this.getdata(); + this.props.comyslElearning(false); + } + } + } @@ -273,7 +291,12 @@ class Elearning extends Component{ }) }; + myupdataleftNav=()=>{ + this.props.updataleftNavfun(); + } render(){ + console.log("Elearning++++++++"); + // console.log(this.props.Chapterupdate); let{description,whethertoedit,isSpin,start_learning,hidestartshixunsreplacevalues,learned,last_shixun,stages,isRender} =this.state; const isNotMembers=this.props.isNotMember();//非课堂成员 const antIcon = ; @@ -359,33 +382,30 @@ class Elearning extends Component{ {/*简介*/} -
              -
              - 简介 -
              -
              -

              -

              -
              + {/*
              */} + {/*
              */} + {/* 简介*/} + {/*
              */} + {/*
              */} + {/*

              */} + {/*

              */} + {/*
              */} -
              + {/*
              */}
            • -
              - { - stages===undefined||stages===JSON.stringify("[]")||stages.length===0? - - : +
              +
              {/*开始学习*/} - this.Startlearningtwo()} Myreload={()=>this.Myreload()} Tojoinclass={()=>this.Tojoinclass()}> + this.Startlearningtwo()} Myreload={()=>this.Myreload()} Tojoinclass={()=>this.Tojoinclass()} getPathCardsList={()=>this.getdata()} >
              - } +
              diff --git a/public/react/src/modules/courses/elearning/YslDetailCards.js b/public/react/src/modules/courses/elearning/YslDetailCards.js index eef44346e..4b295f118 100644 --- a/public/react/src/modules/courses/elearning/YslDetailCards.js +++ b/public/react/src/modules/courses/elearning/YslDetailCards.js @@ -4,7 +4,10 @@ import { Tooltip,Modal,Icon,Spin,message} from 'antd'; import '../../paths/ShixunPaths.css'; import axios from 'axios'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; - +import DetailCardsEditAndEdit from '../../paths/PathDetail/DetailCardsEditAndEdit'; +import DetailCardsEditAndAdd from "../../paths/PathDetail/DetailCardsEditAndAdd"; +import Modals from "../../modals/Modals"; +import NoneData from "../coursesPublic/NoneData"; class YslDetailCards extends Component{ constructor(props){ super(props) @@ -17,7 +20,23 @@ class YslDetailCards extends Component{ shixunsmessage:"", startshixunCombattype:false, isSpin:false, + idsum:undefined, + pathCardsedittype:false, + pathid:undefined, + editbuttomtype:false, + editbuttomtypeadd:false, + pathlistedit:undefined, + delecttype:false, + Modalstype:false, + Modalstopval:'', + Modalsbottomval:'', } + //idsum 是否点击这个 + //pathCardsedittype 是否是在编辑模式 + //editbuttomtypeadd 是否已经是编辑模式 + //pathid课堂id + //pathlistedit 编辑返回的数据 + } showparagraph =(key,index)=>{ @@ -90,6 +109,10 @@ class YslDetailCards extends Component{ }; componentDidMount(){ + let pathid=this.props.match.params.coursesId; + this.setState({ + pathid:pathid + }) } @@ -125,14 +148,194 @@ class YslDetailCards extends Component{ this.setState({ startshixunCombattype:false }) + }; + // 关卡的上移下移操作 + operations = (url) => { + let newurl = url+".json" + axios.get(newurl).then((response) => { + if(response.data.status===1){ + this.props.getPathCardsList(); + } + }).catch((error) => { + console.log(error); + }) + + }; + + //章节下移 + chapterdown=(id)=>{ + let url=`/course_stages/${id}/down_position.json`; + axios.post(url).then((response) => { + if(response){ + if(response.data){ + if(response.data.status===0){ + this.props.showNotification(`下移成功`); + this.props.getPathCardsList(); + }else{ + this.props.showNotification(`下移失败`); + } + }else{ + this.props.showNotification(`下移失败`); + } + }else { + this.props.showNotification(`下移失败`); + } + }).catch((error) => { + console.log(error) + }); + }; + + //章节上移 + chapterup=(id)=>{ + let url=`/course_stages/${id}/up_position.json`; + axios.post(url).then((response) => { + if(response){ + if(response.data){ + if(response.data.status===0){ + this.props.showNotification(`上移成功`); + this.props.getPathCardsList(); + }else{ + this.props.showNotification(`上移失败`); + } + }else{ + this.props.showNotification(`上移失败`); + } + }else{ + this.props.showNotification(`上移失败`); + } + }).catch((error) => { + console.log(error) + }); + }; + + + + //确认的 + updatapathCardsedit=()=>{ + this.setState({ + idsum:undefined, + pathCardsedittype:false, + editbuttomtype:false, + editbuttomtypeadd:false + }) + this.props.getPathCardsList(); + this.props.myupdataleftNavs(); + // this.props.updatadetailInfoLists(); + }; + //取消的 + editeditbuttomtypecanle=()=>{ + this.setState({ + editbuttomtype:true, + editbuttomtypeadd:false + + }) + } + //编辑用 + pathCardsedit=(key,pathid)=>{ + + let url=`/course_stages/${pathid}/edit.json`; + axios.get(url).then((result)=>{ + if(result){ + if(result.status===200){ + this.setState({ + idsum:key, + pathCardsedittype:true, + pathlistedit:result.data, + editbuttomtype:true, + editbuttomtypeadd:true + }) + } + } + }).catch((error)=>{ + console.log(error); + }) + + }; + //删除用的 + delectpathCardsedit=(id)=>{ + + this.setState({ + Modalstype:true, + Modalstopval:'是否删除该章节?', + Modalsbottomval:'', + editdelectid:id, + delecttype:true, + }) + + } + cardsModalcancel=()=>{ + this.setState({ + Modalstype:false, + Modalstopval:'', + Modalsbottomval:'', + editdelectid:undefined + }) + } + cardsModalsave=()=>{ + debugger + this.setState({ + Modalstype:false, + Modalstopval:'', + Modalsbottomval:'', + editdelectid:undefined + }) + } + delectpathCardseditfun=()=>{ + let {delecttype,editdelectid}=this.state; + let id=editdelectid; + if(delecttype===true){ + let url =`/course_stages/${id}.json` + axios.delete(url).then((response) => { + if(response){ + if(response.data){ + if(response.data.status===0){ + this.setState({ + idsum:undefined, + pathCardsedittype:false, + Modalstype:false, + Modalstopval:'', + Modalsbottomval:'', + delecttype:false, + editdelectid:undefined + }) + + this.updatapathCardsedit() + this.props.showNotification(`删除成功`); + this.props.myupdataleftNavs(); + }else { + this.props.showNotification(`删除失败`); + } + }else{ + this.props.showNotification(`删除失败`); + } + }else { + this.props.showNotification(`删除失败`); + } + + }).catch((error) => { + console.log(error) + }) + } + } render(){ - let{showparagraph,showparagraphkey,showparagraphindex,hidestartshixunsreplacevalue} =this.state; - let { stages }=this.props; + let{showparagraph,showparagraphkey,showparagraphindex,hidestartshixunsreplacevalue,idsum,pathCardsedittype,pathid,Modalstype,Modalstopval,Modalsbottomval,delecttype,pathlistedit,editbuttomtypeadd,editbuttomtype} =this.state; + let { stages ,subject_id}=this.props; const antIcon = ; + // console.log("pathCardsedittype"); + // console.log(pathCardsedittype); + // console.log(editbuttomtype); + // console.log("this.props.isAdmin"); + // console.log(this.props.isAdmin()); + // console.log(this.state.delecttype); return( -
              +
              + { + stages===undefined||stages===JSON.stringify("[]")||stages.length===0? + "" + : +
              + + + - { - stages && stages.map((item,key)=>{ - return( -
              -

              - - - - {item.stage_name} + { + this.props.isStudent()===true&&(stages===undefined||stages===JSON.stringify("[]")||stages.length===0)? + + : + "" + } + { + stages && stages.map((item,key)=>{ + + return( +

              +

              -

              -
              -

              {item.stage_description}

              + + + + {item.stage_name} + { + idsum===key&&pathCardsedittype===true?'': + + this.props.isAdmin()==true? + + + { editbuttomtype===true?'': + this.pathCardsedit(key, item.stage_id)}> + + + } + + { + stages.length=== key+1?"":this.chapterdown(item.stage_id)}> + + + + + } + + + {key===0?"": + this.chapterup(item.stage_id)}> + + + + } -
              + :"" + + + } { - item.shixuns_list && item.shixuns_list.map((line,index)=>{ - return( -
              this.showparagraph(key,index)} onMouseLeave={this.hideparagraph}> + idsum === key && pathCardsedittype === true ? + this.props.isAdmin()===true? + this.delectpathCardsedit(item.stage_id)}> + + + + :"" + : '' + } +

              + + { + idsum===key&&pathCardsedittype===true?'': +
              +

              {item.stage_description}

              -
            • +
              + + { + item.shixuns_list && item.shixuns_list.map((line,index)=>{ + return( +
              this.showparagraph(key,index)} onMouseLeave={this.hideparagraph}> + +
            • { @@ -211,36 +484,70 @@ class YslDetailCards extends Component{ : } - + {key+1}-{index+1}  {line.shixun_name} -
            • - { - this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"? -
            • 暂未公开
            • - : -
            • +
            • { - showparagraphkey===key&&showparagraphindex===index?:"" + this.props.current_user&&this.props.current_user.admin===false&&line.shixun_status==="暂未公开"? +
            • 暂未公开
            • + : +
            • + { + showparagraphkey===key&&showparagraphindex===index?:"" + } + +
            • } +
              ) + }) + } +
              +
              + } + { + this.props.isAdmin()===true? + + :"" + } - - } -
              ) - }) - } -
              -
              - ) - }) - } + ) + }) + }
              + } + { editbuttomtypeadd===true?'':this.props.isAdmin()===true? + + :"" + } + +
              ) } } -export default YslDetailCards; \ No newline at end of file +export default YslDetailCards; +// detailInfoList以前实训课堂做权限判断的作用 this.props.subject_id \ No newline at end of file diff --git a/public/react/src/modules/courses/exercise/Ecerciseallbackagain.js b/public/react/src/modules/courses/exercise/Ecerciseallbackagain.js index 0deddfacf..35556da54 100644 --- a/public/react/src/modules/courses/exercise/Ecerciseallbackagain.js +++ b/public/react/src/modules/courses/exercise/Ecerciseallbackagain.js @@ -157,6 +157,42 @@ class Ecerciseallbackagain extends Component{ console.log() return(
              + + .greybackHead{ + padding:0px 30px; + } + .fontlefts{text-align: left;} + `} +
              学生将得到一次重新答题的机会,现有的答题情况将被清空
              • 姓名
              • @@ -182,7 +219,7 @@ class Ecerciseallbackagain extends Component{
              {datalist===undefined?"": -
                @@ -190,7 +227,7 @@ class Ecerciseallbackagain extends Component{ { datalist.map((item,key)=>{ return( -
                +
              • - + {item.user_name}
              • @@ -220,7 +261,7 @@ class Ecerciseallbackagain extends Component{ {onChangetype===true?"清除":"全选"}
              • -
                + diff --git a/public/react/src/modules/courses/exercise/Exercise.js b/public/react/src/modules/courses/exercise/Exercise.js index 2bc646fb3..7662b2c21 100644 --- a/public/react/src/modules/courses/exercise/Exercise.js +++ b/public/react/src/modules/courses/exercise/Exercise.js @@ -338,7 +338,8 @@ class Exercise extends Component{ checkBoxValues:[], Modalstypeloding:false }) - this.InitList(type,StudentList_value,page,limit) + this.InitList(type,StudentList_value,page,limit); + this.props.updataleftNavfun(); } }).catch((error)=>{ console.log(error); diff --git a/public/react/src/modules/courses/exercise/ExerciseDisplay.js b/public/react/src/modules/courses/exercise/ExerciseDisplay.js index a0296476f..42702e9cb 100644 --- a/public/react/src/modules/courses/exercise/ExerciseDisplay.js +++ b/public/react/src/modules/courses/exercise/ExerciseDisplay.js @@ -53,11 +53,17 @@ class ExerciseDisplay extends Component{ componentDidMount = () => { const Id = this.props.match.params.Id if (Id) { - const url = `/exercises/${Id}.json` + const url = `/${this.props.urlPath || 'exercises'}/${Id}.json` axios.get(url) .then((response) => { - if (response.data.status == 0) { - this.setState({...response.data}) + if (response.data.exercise) { + response.data.exercise.exercise_description = response.data.exercise.exercise_description || response.data.exercise.description + response.data.exercise.exercise_name = response.data.exercise.exercise_name || response.data.exercise.name + response.data.exercise.exercise_status = response.data.exercise.exercise_status == undefined ? 1 : response.data.exercise.exercise_status + this.setState({...response.data}) + this.props.detailFetchCallback && this.props.detailFetchCallback(response); + } else { + this.props.detailFetchCallback && this.props.detailFetchCallback(response); } }) .catch(function (error) { diff --git a/public/react/src/modules/courses/exercise/ExerciseNew.js b/public/react/src/modules/courses/exercise/ExerciseNew.js index 017fff71e..80f837686 100644 --- a/public/react/src/modules/courses/exercise/ExerciseNew.js +++ b/public/react/src/modules/courses/exercise/ExerciseNew.js @@ -5,440 +5,63 @@ import { Slider, Button, Upload, Icon, Rate, Checkbox, message, Row, Col, Select, Modal, Tooltip } from 'antd'; -import { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common' -import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; import axios from 'axios' // import './board.css' -import "../common/formCommon.css" +// import "../common/formCommon.css" // import { RouteHOC } from './common.js' -import CBreadcrumb from '../common/CBreadcrumb' -import {getUrl, ActionBtn} from 'educoder'; -import SingleEditor from './new/SingleEditor' -import SingleDisplay from './new/SingleDisplay' -import JudgeEditor from './new/JudgeEditor' -import JudgeDisplay from './new/JudgeDisplay' -import NullEditor from './new/NullEditor' -import NullDisplay from './new/NullDisplay' -import MainEditor from './new/MainEditor' -import MainDisplay from './new/MainDisplay' -import ShixunEditor from './new/ShixunEditor' -import ShixunDisplay from './new/ShixunDisplay' +// import { Q_TYPE_SINGLE, Q_TYPE_MULTI, Q_TYPE_JUDGE, Q_TYPE_NULL, Q_TYPE_MAIN, Q_TYPE_SHIXUN } from './new/common' +// import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; +// import CBreadcrumb from '../common/CBreadcrumb' +import {getUrl, ActionBtn, CBreadcrumb} from 'educoder'; + +// import SingleEditor from './new/SingleEditor' +// import SingleDisplay from './new/SingleDisplay' +// import JudgeEditor from './new/JudgeEditor' +// import JudgeDisplay from './new/JudgeDisplay' +// import NullEditor from './new/NullEditor' +// import NullDisplay from './new/NullDisplay' +// import MainEditor from './new/MainEditor' +// import MainDisplay from './new/MainDisplay' +// import ShixunEditor from './new/ShixunEditor' +// import ShixunDisplay from './new/ShixunDisplay' -import ShixunChooseModal from '../coursesPublic/ShixunChooseModal' import update from 'immutability-helper' import './new/common.css' import '../css/Courses.css' + +import ExerciseNewCommon from './ExerciseNewCommon' const { TextArea } = Input; -const confirm = Modal.confirm; -const $ = window.$ -const { Option } = Select; -const TITLE_MAX_LENGTH = 60; + class ExerciceNew extends Component{ constructor(props){ super(props); this.state = { - exercise_questions: [], - exercise_name: '', - exercise_description: '', - exercise_types: {}, - editMode: !this.props.match.params.Id, - } - } - - // 已发布试卷编辑保存的确认弹框 - changeScore = (question_id,answerArray) =>{ - this.props.confirm({ - content:'修改了标准答案', - subContent:"是否重新计算学生答题的成绩?", - onOk:()=>{ - this.sureChangeScore(question_id,answerArray) - }, - onCancel:()=>{ - this.addSuccess(); - } - }) - } - - // 已发布试卷修改答案确认修改分数 - sureChangeScore = (question_id,answerArray) =>{ - let url=`/exercise_questions/${question_id}/update_scores.json` - axios.post((url),{ - standard_answers:answerArray - }).then((result)=>{ - if(result){ - this.props.showNotification(`${result.data.message}`); - this.addSuccess(); - } - }).catch((error)=>{ - console.log(error); - }) - } - - fetchExercise = () => { - const Id = this.props.match.params.Id - this.isEdit = !!Id - if (Id) { - const url = `/exercises/${Id}/edit.json` - axios.get(url) - .then((response) => { - if (response.data.status == 0) { - const { exercise, ...others } = response.data - this.setState({ - ...exercise, - ...others, - editMode: false - }) - } - }) - .catch(function (error) { - console.log(error); - }); - } else { - const courseId=this.props.match.params.coursesId; - - const newUrl = `/courses/${courseId}/exercises/new.json` - axios.get(newUrl) - .then((response) => { - if (response.data.status == 0) { - this.setState({ - ...response.data - }) - } - }) - .catch(function (error) { - console.log(error); - }); + } } componentDidMount = () => { - this.fetchExercise() - } - handleSubmit = (e) => { } - onSaveExercise = () => { - const { exercise_name, exercise_description } = this.state; - const exercise_id = this.props.match.params.Id - const courseId = this.props.match.params.coursesId - if (this.isEdit) { - const editUrl = `/exercises/${exercise_id}.json` - axios.put(editUrl, { - exercise_name, - exercise_description - }) - .then((response) => { - if (response.data.status == 0) { - this.setState({editMode: false}) - this.props.showNotification('试卷编辑成功') - } - }) - .catch(function (error) { - console.log(error); - }); - } else { - const url = `/courses/${courseId}/exercises.json` - axios.post(url, { - exercise_name, - exercise_description - }) - .then((response) => { - if (response.data.status == 0) { - this.setState({editMode: false}) - - this.props.showNotification('试卷新建成功') - const exercise_id = response.data.data.exercise_id; - this.isEdit = true; - - this.props.history.replace(`/courses/${courseId}/exercises/${exercise_id}/edit`); - - } - }) - .catch(function (error) { - console.log(error); - }); - } - } - exercise_name_change = (e) => { - this.setState({exercise_name: e.target.value}) - } - exercise_description_change = (e) => { - this.setState({exercise_description: e.target.value}) - } - // #问题的类型,0为单选题,1为多选题,2为判断题,3为填空题,4为主观题,5为实训题 - _checkIsEditing = () => { - if (this.editingId && $(this.editingId).length ) { - this.props.showNotification('请先保存或取消当前正在编辑的问题。') - $("html").animate({ scrollTop: $(this.editingId).offset().top - 100}) - return true - } - return false - } - onEditorCancel = () => { - this.editingId = null; - // 找到编辑或新建的item,新建就删掉item,编辑就isNew改为false - const { exercise_questions } = this.state - let index = -1; - for(let i = 0; i < exercise_questions.length; i++) { - if (exercise_questions[i].isNew == true) { - index = i; - break; - } - } - if (exercise_questions[index].question_id) { // 编辑 - this.setState( - (prevState) => ({ - exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: false}}}) - // update(prevState.exercise_questions, {$splice: [[index, 1]]}) - }) - ) - } else { // 新建 - this.setState( - (prevState) => ({ - exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) - }) - ) - } - } - addQuestion = (question_id_to_insert_after, type) => { - if (!this.isEdit) { - this.props.showNotification('请先输入试卷标题,并保存试卷') - return; - } - if (this._checkIsEditing()) { - return; - } - if (type == Q_TYPE_SHIXUN) { - this.addShixun(question_id_to_insert_after) - } else { - this.addEditingQuestion(type, question_id_to_insert_after) - } - } - chooseShixun = (array) => { - this.addEditingQuestion(Q_TYPE_SHIXUN, this.question_id_to_insert_after, { - shixun_id: array[0] - }) - } - chooseShixunSuccess = () => { - this.refs.shixunChooseModal.setVisible(false) - } - addShixun = (question_id_to_insert_after) => { - if (!this.isEdit) { - this.props.showNotification('请先输入试卷标题,并保存试卷') - return; - } - // TODO 弹框选择实训 - if (this._checkIsEditing()) { - return; - } - this.refs.shixunChooseModal.setVisible(true) - this.question_id_to_insert_after = question_id_to_insert_after; - return; - // 拉取实训items - this.addEditingQuestion(Q_TYPE_SHIXUN, question_id_to_insert_after, { - shixun_id: 50 - }) - } - editQestion = (index) => { - if (this._checkIsEditing()) { - return; - } - this.editingId = `#question_${index}` - - this.setState( - (prevState) => ({ - exercise_questions : update(prevState.exercise_questions, {[index]: { isNew: {$set: true}}}) - }) - ) - } - onSort = (index, question_id, isUp) => { - if (this._checkIsEditing()) { - return; - } - const url = `/exercise_questions/${question_id}/up_down.json` - axios.post(url, { opr: isUp ? 'up' : 'down'}) - .then((response) => { - if (response.data.status == 0) { - // this.props.showNotification('移动成功') - this.fetchExercise() - } - }) - .catch(function (error) { - console.log(error); - }); - } - onSortDown = (index, question_id) => { - this.onSort(index, question_id, false) - } - onSortUp = (index, question_id) => { - this.onSort(index, question_id, true) - } - getInitScore = (question_type, question_id_to_insert_after) => { - /** - 1.每个题型的首个题目默认值规则如下: - 选择题:5分 01 - 判断题:2分 2 - 填空题:2分 3 - 简答题:10分 4 - 实训题:每个关卡5分 5 - */ - let init_question_score = 0; - if (question_type == 0 || question_type == 1) { - init_question_score = 5 - } else if (question_type == 2) { - init_question_score = 2 - } else if (question_type == 3) { - init_question_score = 2 - } else if (question_type == 4) { - init_question_score = 10 - } else if (question_type == 5) { - init_question_score = 5 - } - const _indexBefore = question_id_to_insert_after ? this.findIndexById(question_id_to_insert_after) : this.state.exercise_questions.length - 1 - for (let i = _indexBefore; i >= 0; i--) { - if(this.state.exercise_questions[i].question_type == question_type) { - init_question_score = this.state.exercise_questions[i].question_score - break; - } - } - return init_question_score; - } - addEditingQuestion = (question_type, question_id_to_insert_after, otherAttributes) => { - - let init_question_score = this.getInitScore(question_type, question_id_to_insert_after) - - let questionObj = { - question_type: question_type, // 需要这个通过类型判断 - init_question_score: init_question_score, - isNew: true, // 新建或编辑,用是否有id区分是新建还是编辑 - question_id_to_insert_after, - ...otherAttributes - } - const { exercise_questions } = this.state; - let new_exercise_questions = exercise_questions.slice(0) - let newIndex = new_exercise_questions.length; - - if (question_id_to_insert_after) { - const _indexBefore = this.findIndexById(question_id_to_insert_after) - new_exercise_questions.splice(_indexBefore + 1, 0, questionObj) - newIndex = _indexBefore + 1 - } else { - new_exercise_questions.push(questionObj) - } - this.editingId = `#question_${newIndex}` - this.setState({ exercise_questions: new_exercise_questions }, () => { - setTimeout(() => { - $(this.editingId).length && $("html").animate({ scrollTop: $(this.editingId).offset().top - 100}) - }, 500) - }) - } - findIndexById = (id) => { - const { exercise_questions } = this.state - for(let i = 0; i < exercise_questions.length; i++) { - if (exercise_questions[i].question_id == id) { - return i; - } - } - } - onQestionDelete = (question_id) => { - this.props.confirm({ - content: `确认要删除这个问题吗?`, - onOk: () => { - const url = `/exercise_questions/${question_id}.json` - axios.delete(url) - .then((response) => { - if (response.data.status == 0) { - this.props.showNotification('删除成功') - this.fetchExercise() - - // const { exercise_questions } = this.state - // const index = this.findIndexById(question_id) - - // this.setState( - // (prevState) => ({ - // exercise_questions : update(prevState.exercise_questions, {$splice: [[index, 1]]}) - // }) - // ) - } - }) - .catch(function (error) { - console.log(error); - }); - } - }) - } - addSuccess = () => { - this.editingId = null; - this.fetchExercise() - } - goToPreview = () => { - const exercise_id = this.props.match.params.Id - const courseId = this.props.match.params.coursesId - this.props.history.push(`/courses/${courseId}/exercises/${exercise_id}/student_exercise_list?tab=2`) + initData = (data) => { + this.setState({left_banner_id: data.left_banner_id}) } render() { - let { exercise_name, exercise_description, course_id, exercise_types, - exercise_questions, left_banner_id } = this.state; - // if (this.isEdit && !exercise_types) { - // return '' - // } - // const { getFieldDecorator } = this.props.form; - const { q_counts, q_scores, q_doubles, q_doubles_scores, q_judges, q_judges_scores, - q_mains, q_mains_scores, q_nulls, q_nulls_scores, q_shixuns, q_shixuns_scores, q_singles, q_singles_scores} = exercise_types; - const formItemLayout = { - labelCol: { - xs: { span: 24 }, - // sm: { span: 8 }, - sm: { span: 24 }, - }, - wrapperCol: { - xs: { span: 24 }, - // sm: { span: 16 }, - sm: { span: 24 }, - }, - }; + let { left_banner_id } = this.state; + const { current_user } = this.props - const isAdmin = this.props.isAdmin() + const courseId=this.props.match.params.coursesId; - const exercise_id = this.props.match.params.Id const isEdit = this.isEdit - const commonHandler = { - onQestionDelete: this.onQestionDelete, - addSuccess: this.addSuccess, - addQuestion: this.addQuestion, - onEditorCancel: this.onEditorCancel, - changeScore:this.changeScore, - editQestion: this.editQestion, - onSortDown: this.onSortDown, - onSortUp: this.onSortUp, - displayCount: exercise_questions.length, - exercise_status: this.state.exercise_status, - exerciseIsPublish: this.state.exercise_status >= 2 - } + return(
                - - +
                { current_user &&

                - {!this.state.editMode && } - {this.state.editMode &&
                -
                - - {/* {getFieldDecorator('subject', { - rules: [{ - required: true, message: '请输入标题', - }, { - max: 20, message: '最大限制为20个字符', - }], - })( */} - - - {/* )} */} - - - - {/* {getFieldDecorator('select_board_id', { - // initialValue: '3779', - })( */} - +
                :"" }
                diff --git a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js index 33fd0a748..60065f43e 100644 --- a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js +++ b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js @@ -19,6 +19,7 @@ import '../css/busyWork.css' import '../poll/pollStyle.css' import moment from 'moment'; import 'moment/locale/zh-cn'; +import './yslexercisetable.css'; import {getImageUrl, toPath} from 'educoder'; import CheckBoxGroup from "../../page/component/CheckBoxGroup"; @@ -70,12 +71,13 @@ class Studentshavecompletedthelist extends Component { key: 'number', align: 'center', className: "edu-txt-center font-14", + width:'100px', render: (text, record) => ( {record.number === "--" ? - {record.number} + {record.number} : - {record.number} + {record.number} } @@ -86,13 +88,16 @@ class Studentshavecompletedthelist extends Component { dataIndex: 'name', key: 'name', align: 'center', - className: "edu-txt-center font-14", + className: "edu-txt-center font-14 maxnamewidth110", + width:'100px', render: (text, record) => ( - + {record.name === "--" ? - {record.name} + {record.name} : - {record.name} + {record.name} } @@ -103,24 +108,30 @@ class Studentshavecompletedthelist extends Component { dataIndex: 'stduynumber', key: 'stduynumber', align: 'center', - className: "edu-txt-center font-14", + className: "edu-txt-center font-14 maxnamewidth175", + width:'175px', render: (text, record) => ( - + {record.stduynumber === null ? -- : record.stduynumber === "" ? -- : - {record.stduynumber} + {record.stduynumber} } @@ -131,25 +142,28 @@ class Studentshavecompletedthelist extends Component { key: 'classroom', dataIndex: 'classroom', align: 'center', - className: "edu-txt-center font-14", - width:"260px", + className: "edu-txt-center font-14 maxnamewidth255", + width:'255px', render: (text, record) => ( - + {record.classroom === null ? -- : record.classroom === "" ? -- : - {record.classroom} + {record.classroom} } @@ -161,14 +175,19 @@ class Studentshavecompletedthelist extends Component { key: 'submitstate', align: 'center', className: "edu-txt-center font-14", + width:'98px', render: (text, record) => ( - + {record.submitstate} ) @@ -180,12 +199,15 @@ class Studentshavecompletedthelist extends Component { key: 'updatetime', align: 'center', className: "edu-txt-center font-14", + width:'175px', render: (text, record) => ( - + {record.updatetime === "--" ? - {record.updatetime} + {record.updatetime} : - {record.updatetime} + {record.updatetime} } ), @@ -196,29 +218,35 @@ class Studentshavecompletedthelist extends Component { key: 'completion', align: 'center', className: "edu-txt-center font-14", + width:'98px', render: (text, record) => ( { record.completion === "--" ? {record.completion} : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", + width:'98px', } : parseInt(record.completion) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center", + width:'98px', } : parseInt(record.completion) <= 60 ? { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center", + width:'98px', } : { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center", + width:'98px', }}>{record.completion} } @@ -231,26 +259,31 @@ class Studentshavecompletedthelist extends Component { key: 'levelscore', align: 'center', className: "edu-txt-center font-14", + width:'99px', render: (text, record) => ( {record.levelscore === "--" ? {record.levelscore} : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", + width:'99px', } : parseInt(record.levelscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center", + width:'99px', } : parseInt(record.levelscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center" - } : {"color": '#747A7F', "text-align": "center"}}>{record.levelscore} + color: '#747A7F', + textAlign: "center", + width:'99px', + } : {color: '#747A7F', textAlign: "center",width:'99px'}}>{record.levelscore} } ) @@ -268,25 +301,25 @@ class Studentshavecompletedthelist extends Component {
                未评分
                }> {record.efficiencyscore} : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center" } : parseInt(record.efficiencyscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center" } : parseInt(record.efficiencyscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center" }}>{record.efficiencyscore} } @@ -300,15 +333,11 @@ class Studentshavecompletedthelist extends Component { key: 'number', align: 'center', className: "edu-txt-center tabletd font-14", + width:'100px', render: (text, record) => ( { - record.number === "--" ? - {record.number} - - : - {record.number} - + } ) @@ -318,14 +347,15 @@ class Studentshavecompletedthelist extends Component { dataIndex: 'name', key: 'name', align: 'center', - className: "edu-txt-center tabletd font-14", + className: "edu-txt-center tabletd font-14 maxnamewidth110", + width:'100px', render: (text, record) => ( - + { record.name === "--" ? - {record.name} + {record.name} : - {record.name} + {record.name} } @@ -336,25 +366,31 @@ class Studentshavecompletedthelist extends Component { dataIndex: 'stduynumber', key: 'stduynumber', align: 'center', - className: "edu-txt-center tabletd font-14", + className: "edu-txt-center tabletd font-14 maxnamewidth175", + width:'175px', render: (text, record) => ( - + {record.stduynumber === null ? -- : record.stduynumber === "" ? -- : - {record.stduynumber} + {record.stduynumber} } @@ -365,23 +401,28 @@ class Studentshavecompletedthelist extends Component { key: 'classroom', dataIndex: 'classroom', align: 'center', - className: "edu-txt-center tabletd font-14", - width:"260px", + className: "edu-txt-center tabletd font-14 maxnamewidth255", + width:'255px', render: (text, record) => ( - + {record.classroom === null ? --: record.classroom === "" ? --: - {record.classroom} + {record.classroom} } @@ -393,14 +434,17 @@ class Studentshavecompletedthelist extends Component { key: 'submitstate', align: 'center', className: "edu-txt-center tabletd font-14", + width:'98px', render: (text, record) => ( - + {record.submitstate} ) @@ -412,12 +456,15 @@ class Studentshavecompletedthelist extends Component { key: 'updatetime', align: 'center', className: "edu-txt-center tabletd font-14", + width:'175px', render: (text, record) => ( - + {record.updatetime === "--"? - -- + -- : - {record.updatetime} + {record.updatetime} } ), @@ -428,29 +475,35 @@ class Studentshavecompletedthelist extends Component { key: 'completion', align: 'center', className: "edu-txt-center tabletd font-14", + width:'98px', render: (text, record) => ( {record.completion === "--" ? -- : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", + width:'98px', } : parseInt(record.completion) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center", + width:'98px', } : parseInt(record.completion) <= 60 ? { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center", + width:'98px', } : { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center", + width:'98px', }}>{record.completion} } @@ -462,26 +515,31 @@ class Studentshavecompletedthelist extends Component { key: 'levelscore', align: 'center', className: "edu-txt-center tabletd font-14", + width:'99px', render: (text, record) => ( {record.levelscore === "--"? -- : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", + width:'99px' } : parseInt(record.levelscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center", + width:'99px' } : parseInt(record.levelscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center" - } : {"color": '#747A7F', "text-align": "center"}}>{record.levelscore} + color: '#747A7F', + textAlign: "center", + width:'99px' + } : {color: '#747A7F', textAlign: "center", width:'99px'}}>{record.levelscore} } ) @@ -500,23 +558,23 @@ class Studentshavecompletedthelist extends Component {
                未评分
                }> -- : 90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center" + color: '#FF6800', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center" + color: '#747A7F', + textAlign: "center", }}>{record.efficiencyscore} } @@ -535,9 +593,9 @@ class Studentshavecompletedthelist extends Component { { record.number=== "--"? - -- + -- : - {record.number} + {record.number} } @@ -553,9 +611,9 @@ class Studentshavecompletedthelist extends Component { { record.name === "--" ? - -- + -- : - {record.name} + {record.name} } ) @@ -570,18 +628,18 @@ class Studentshavecompletedthelist extends Component { {record.stduynumber === null ? -- : record.stduynumber === "" ? -- : {record.stduynumber} } @@ -599,16 +657,16 @@ class Studentshavecompletedthelist extends Component { {record.classroom === null ? -- : record.classroom === "" ? -- : {record.classroom} } @@ -624,11 +682,11 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.submitstate} ) @@ -644,10 +702,10 @@ class Studentshavecompletedthelist extends Component { { record.updatetime === "--" ? - -- + -- : - {record.updatetime} + {record.updatetime} } @@ -664,22 +722,22 @@ class Studentshavecompletedthelist extends Component { { record.completion === "--"? -- : 90 ? { - "color": '#DD1717', - "text-align": "center", + color: '#DD1717', + textAlign: "center", } : parseInt(record.completion) <= 90 ? { - "color": '#FF6800', - "text-align": "center", + color: '#FF6800', + textAlign: "center", } : parseInt(record.completion) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", }}>{record.completion} } @@ -697,19 +755,19 @@ class Studentshavecompletedthelist extends Component { { record.levelscore === "--" ? -- : 90 ? { - "color": '#DD1717', - "text-align": "center", + color: '#DD1717', + textAlign: "center", } : parseInt(record.levelscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center", + color: '#FF6800', + textAlign: "center", } : parseInt(record.levelscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", - } : {"color": '#747A7F', "text-align": "center"}}>{record.levelscore} + color: '#747A7F', + textAlign: "center", + } : {color: '#747A7F', textAlign: "center"}}>{record.levelscore} } @@ -729,23 +787,23 @@ class Studentshavecompletedthelist extends Component {
                未评分
                }> -- : 90 ? { - "color": '#DD1717', - "text-align": "center", + color: '#DD1717', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center", + color: '#FF6800', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", }}>{record.efficiencyscore} } @@ -760,11 +818,11 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.operating==="--"? - {record.operating} + {record.operating} :record.submitstate === "未提交"? - -- + -- : - {record.operating} } @@ -789,9 +847,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.number === "--" ? - -- + -- : - {record.number} + {record.number} } ) @@ -805,9 +863,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.name==="--"? - {record.name} + {record.name} : - {record.name} + {record.name} } ) @@ -821,9 +879,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.stduynumber === "--" ? - {record.stduynumber} + {record.stduynumber} : - {record.stduynumber} + {record.stduynumber} } ), @@ -838,9 +896,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.classroom==="--"? - {record.classroom} + {record.classroom} : - {record.classroom} + {record.classroom} } ) @@ -854,11 +912,11 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.submitstate} @@ -874,9 +932,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.updatetime==="--"? - -- + -- : - {record.updatetime} + {record.updatetime} } ), @@ -890,9 +948,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.completion=== "--"? - -- + -- : - {record.completion} + {record.completion} } ) @@ -906,9 +964,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.levelscore==="--"? - -- + -- : - {record.levelscore} + {record.levelscore} } ) @@ -925,22 +983,22 @@ class Studentshavecompletedthelist extends Component {
                未评分
              }> - -- + -- : 90 ? { - "color": '#DD1717', - "text-align": "center", + color: '#DD1717', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center", + color: '#FF6800', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", }}>{record.efficiencyscore} } @@ -955,13 +1013,13 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.finalscore==="--"? - -- :record.submitstate === "未提交"? - -- : - {record.finalscore} } @@ -979,9 +1037,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.number === "--" ? - -- + -- : - {record.number} + {record.number} } ) @@ -995,9 +1053,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.name==="--"? - {record.name} + {record.name} : - {record.name} + {record.name} } ) @@ -1011,9 +1069,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.stduynumber === "--" ? - {record.stduynumber} + {record.stduynumber} : - {record.stduynumber} + {record.stduynumber} } ), @@ -1028,9 +1086,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.classroom==="--"? - {record.classroom} + {record.classroom} : - {record.classroom} + {record.classroom} } ) @@ -1044,11 +1102,11 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.submitstate} @@ -1064,9 +1122,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.updatetime==="--"? - -- + -- : - {record.updatetime} + {record.updatetime} } ), @@ -1080,9 +1138,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.completion=== "--"? - -- + -- : - {record.completion} + {record.completion} } ) @@ -1096,9 +1154,9 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.levelscore==="--"? - -- + -- : - {record.levelscore} + {record.levelscore} } ) @@ -1115,22 +1173,22 @@ class Studentshavecompletedthelist extends Component {
              未评分
              }> - -- + -- : 90 ? { - "color": '#DD1717', - "text-align": "center", + color: '#DD1717', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 90 ? { - "color": '#FF6800', - "text-align": "center", + color: '#FF6800', + textAlign: "center", } : parseInt(record.efficiencyscore) <= 60 ? { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", } : { - "color": '#747A7F', - "text-align": "center", + color: '#747A7F', + textAlign: "center", }}>{record.efficiencyscore} } @@ -1145,13 +1203,13 @@ class Studentshavecompletedthelist extends Component { render: (text, record) => ( {record.finalscore==="--"? - -- :record.submitstate === "未提交"? - -- : - {record.finalscore} } @@ -2554,7 +2612,7 @@ class Studentshavecompletedthelist extends Component {
              {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.total_users}{Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.total_users}个检索结果({Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.exercise_all_users}学生)
              @@ -2565,11 +2623,11 @@ class Studentshavecompletedthelist extends Component {
            @@ -2645,15 +2703,15 @@ class Studentshavecompletedthelist extends Component {
            {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.answer_users}已交 + style={{color: '#FF6800'}}>{Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.answer_users}已交 {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.unanswer_users}未交 + style={{color: "#666666"}}> {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.unanswer_users}未交 {Teacherliststudentlist && Teacherliststudentlist.exercise_types.exercise_end_time === "--" ? "" : - 剩余提交时间:} + 剩余提交时间:} {Teacherliststudentlist && Teacherliststudentlist.exercise_types.exercise_end_time === "--" ? "" : - + {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.exercise_end_time} } @@ -2709,21 +2767,36 @@ class Studentshavecompletedthelist extends Component { " min-width": " 1200px" }}>
            -
            + { + ` + .edu-table .ant-table-tbody > tr > td { + height: 58px; + } + .edu-table .ant-table-thead > tr > th{ + height: 58px; + } + .ysltableows .ant-table-thead > tr > th{ + height: 58px; + } + .ysltableows .ant-table-tbody > tr > td{ + height: 58px; + } + .ysltableows .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 9px; + } + ` + } + +
            - {data === undefined ? "" : } {JSON.stringify(datas) === "[]" ? @@ -2749,15 +2822,15 @@ class Studentshavecompletedthelist extends Component {
            {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.answer_users}已交{Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.answer_users}已交 {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.unanswer_users}未交 + style={{color: "#666666"}}>{Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.unanswer_users}未交 {Teacherliststudentlist && Teacherliststudentlist.exercise_types.exercise_end_time === "--" ? "" : - 剩余提交时间:} + 剩余提交时间:} {Teacherliststudentlist && Teacherliststudentlist.exercise_types.exercise_end_time === "--" ? "" : {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.exercise_end_time}} + style={{color: '#FF6800'}}> {Teacherliststudentlist === undefined ? "0" : Teacherliststudentlist.exercise_types.exercise_end_time}}
            { - this.setState({ donwloading: false }) - console.log('successCallback') - }, - failCallback: (responseHtml, url) => { - this.setState({ donwloading: false }) - console.log('failCallback') - } - }) - this.props.showNotification(`正在下载中`); + this.props.slowDownload(urll) + // this.setState({ donwloading: true }) + // downloadFile({ + // url: urll, + // successCallback: (url) => { + // this.setState({ donwloading: false }) + // console.log('successCallback') + // }, + // failCallback: (responseHtml, url) => { + // this.setState({ donwloading: false }) + // console.log('failCallback') + // } + // }) + // this.props.showNotification(`正在下载中`); // window.open("/api"+url+`?${queryString.stringify(params)}`+ '&export=true', '_blank'); } @@ -380,7 +381,8 @@ class Testpapersettinghomepage extends Component{ 导出:""} diff --git a/public/react/src/modules/courses/exercise/new/JudgeDisplay.js b/public/react/src/modules/courses/exercise/new/JudgeDisplay.js index a6996ed84..d340f5fa4 100644 --- a/public/react/src/modules/courses/exercise/new/JudgeDisplay.js +++ b/public/react/src/modules/courses/exercise/new/JudgeDisplay.js @@ -86,7 +86,7 @@ class JudgeDisplay extends Component{ // 单选 return (
            - + {/* {item.choice_text} */} p{ + line-height:20px; + } `} diff --git a/public/react/src/modules/courses/exercise/new/NullEditor.js b/public/react/src/modules/courses/exercise/new/NullEditor.js index 85a8aa336..dcb310396 100644 --- a/public/react/src/modules/courses/exercise/new/NullEditor.js +++ b/public/react/src/modules/courses/exercise/new/NullEditor.js @@ -124,7 +124,7 @@ class NullEditor extends Component{ }*/ const Id = this.props.match.params.Id if (question_id) { - const editUrl = `/exercise_questions/${question_id}.json` + const editUrl = this.props.getEditQuestionUrl(question_id); axios.put(editUrl, { question_title, question_type: 3, @@ -145,9 +145,10 @@ class NullEditor extends Component{ console.log(error); }); } else { - const url = `/exercises/${Id}/exercise_questions.json` + const url = this.props.getAddQuestionUrl(); axios.post(url, { + exercise_bank_id: Id, question_title, question_type: 3, question_score, diff --git a/public/react/src/modules/courses/exercise/new/ShixunEditor.js b/public/react/src/modules/courses/exercise/new/ShixunEditor.js index 3cc32ce75..6457d256b 100644 --- a/public/react/src/modules/courses/exercise/new/ShixunEditor.js +++ b/public/react/src/modules/courses/exercise/new/ShixunEditor.js @@ -113,7 +113,7 @@ class ShixunEditor extends Component{ }*/ const Id = this.props.match.params.Id if (question_id) { - const editUrl = `/exercise_questions/${question_id}.json` + const editUrl = this.props.getEditQuestionUrl(question_id); axios.put(editUrl, { question_title, question_type: 5, @@ -131,9 +131,10 @@ class ShixunEditor extends Component{ console.log(error); }); } else { - const url = `/exercises/${Id}/exercise_questions.json` + const url = this.props.getAddQuestionUrl(); axios.post(url, { + exercise_bank_id: Id, question_title, question_type: 5, question_scores, @@ -155,10 +156,10 @@ class ShixunEditor extends Component{ this.props.onEditorCancel() } componentDidMount = () => { - const { shixun_id } = this.props; + const { shixun_id, exercise_url } = this.props; // shixun_id const Id = this.props.match.params.Id - const url = `/exercises/${Id}/commit_shixun.json` + const url = `/${exercise_url || 'exercises'}/${Id}/commit_shixun.json` axios.get(url, { params: { shixun_id diff --git a/public/react/src/modules/courses/exercise/new/SingleDisplay.js b/public/react/src/modules/courses/exercise/new/SingleDisplay.js index bce4dc4c1..7159b0ee6 100644 --- a/public/react/src/modules/courses/exercise/new/SingleDisplay.js +++ b/public/react/src/modules/courses/exercise/new/SingleDisplay.js @@ -99,7 +99,7 @@ class SingleDisplay extends Component{ if (question_type == 0) { // 单选 return (
            - {prefix} + {prefix} @@ -110,7 +110,7 @@ class SingleDisplay extends Component{ return (
            - {prefix} + {prefix} diff --git a/public/react/src/modules/courses/exercise/new/SingleEditor.js b/public/react/src/modules/courses/exercise/new/SingleEditor.js index 50e594a59..b3c2842f5 100644 --- a/public/react/src/modules/courses/exercise/new/SingleEditor.js +++ b/public/react/src/modules/courses/exercise/new/SingleEditor.js @@ -123,7 +123,7 @@ class SingleEditor extends Component{ }*/ const Id = this.props.match.params.Id if (question_id) { - const editUrl = `/exercise_questions/${question_id}.json` + const editUrl = this.props.getEditQuestionUrl(question_id); axios.put(editUrl, { question_title, question_type: answerArray.length > 1 ? 1 : 0, @@ -143,9 +143,10 @@ class SingleEditor extends Component{ console.log(error); }); } else { - const url = `/exercises/${Id}/exercise_questions.json` + const url = this.props.getAddQuestionUrl(); axios.post(url, { + exercise_bank_id: Id, question_title, question_type: answerArray.length > 1 ? 1 : 0, question_score, diff --git a/public/react/src/modules/courses/exercise/question/multiple.js b/public/react/src/modules/courses/exercise/question/multiple.js index 4e74b68ce..2e1023faa 100644 --- a/public/react/src/modules/courses/exercise/question/multiple.js +++ b/public/react/src/modules/courses/exercise/question/multiple.js @@ -52,7 +52,7 @@ class Multiple extends Component{ return(

            - {prefix} + {prefix} diff --git a/public/react/src/modules/courses/exercise/question/single.js b/public/react/src/modules/courses/exercise/question/single.js index 5156019d4..e739b8f1c 100644 --- a/public/react/src/modules/courses/exercise/question/single.js +++ b/public/react/src/modules/courses/exercise/question/single.js @@ -46,10 +46,10 @@ class single extends Component{ let prefix = isJudge ? undefined : `${tagArray[key]}.` return(

            - - {prefix} + + {prefix}

            diff --git a/public/react/src/modules/courses/exercise/yslexercisetable.css b/public/react/src/modules/courses/exercise/yslexercisetable.css index e69de29bb..2727ca2ff 100644 --- a/public/react/src/modules/courses/exercise/yslexercisetable.css +++ b/public/react/src/modules/courses/exercise/yslexercisetable.css @@ -0,0 +1,49 @@ +.maxnamewidth100{ + max-width: 100px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth110{ + max-width: 100px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth200{ + max-width: 200px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth145{ + max-width: 145px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth215{ + max-width: 215px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth255{ + max-width: 255px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} +.maxnamewidth175{ + max-width: 175px; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + cursor: default; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/gradinforms/Bullsubdirectory.js b/public/react/src/modules/courses/gradinforms/Bullsubdirectory.js index bc45eeece..496423f73 100644 --- a/public/react/src/modules/courses/gradinforms/Bullsubdirectory.js +++ b/public/react/src/modules/courses/gradinforms/Bullsubdirectory.js @@ -6,6 +6,7 @@ import axios from 'axios'; import TPMMDEditor from "../../tpm/challengesnew/TPMMDEditor"; import moment from "../new/CoursesNew"; import Fileslistitem from "../Resource/Fileslistitem"; +import Modals from "../../modals/Modals"; // 公告栏 class Bullsubdirectory extends Component{ constructor(props){ @@ -19,6 +20,10 @@ class Bullsubdirectory extends Component{ addonAfter:0, eduintits:"", informs:[], + Modalstype:false, + Modalstopval:"是否确认删除?", + ModalCancel:"", + ModalSave:"", } @@ -47,6 +52,61 @@ class Bullsubdirectory extends Component{ } + setModeltrue=()=>{ + this.setState({ + Modalstype:true, + Modalstopval:"是否确认删除?", + ModalCancel:this.cancelmodel, + ModalSave:this.saveonOpen, + }) + } + + cancelmodel=()=>{ + //取消 + this.setState({ + Modalstype:false, + Modalstopval:"是否确认删除?", + ModalCancel:"", + ModalSave:"", + }) + } + + saveonOpen=()=>{ + //确认 + // / + // 删除公告 + var id=this.props.match.params.coursesId + const url =`/courses/${id}/delete_informs.json`; + axios.delete(url, { data: { + inform_id: this.props.id + }}) + .then((response) => { + if(response){ + if(response.data){ + if(response.data.status===0){ + this.setState({ + Modalstype:false, + Modalstopval:"是否确认删除?", + ModalCancel:"", + ModalSave:"", + }) + this.props.showNotification(`删除成功`); + this.props.getinputdata(); + }else{ + this.props.showNotification(`删除失败`); + } + }else{ + this.props.showNotification(`删除失败`); + } + } + + }) + .catch(function (error) { + console.log(error); + this.props.showNotification(`删除失败`); + }); + } + bianji = (bians)=>{ this.setState({ @@ -113,7 +173,7 @@ class Bullsubdirectory extends Component{ } var url = `/courses/${id}/update_informs.json`; axios.post(url,{ - inform_id:this.state.id, + inform_id:this.props.id, name:titname, description:values.description, }).then((result) => { @@ -154,12 +214,20 @@ class Bullsubdirectory extends Component{ render(){ let{description,whethertoeditysl,addonAfter,eduintits,informs,isSpinysl} =this.state; - let{myname,mydescription}=this.props; + let{myname,mydescription,id}=this.props; const {getFieldDecorator} = this.props.form; - + // console.log("Bullsubdirectory"); + // console.log(this.props.isAdmin()); + // console.log(this.props.yslbool); return(
            + {this.state.Modalstype&&this.state.Modalstype===true?:""}
            { @@ -171,11 +239,30 @@ class Bullsubdirectory extends Component{ {myname}
            - + { this.props.isAdmin() === true ? (this.props.yslbool===false? + + 编辑 +
            }> this.bianji(true)}> + + : + "" + ) + :"" + } + + + { + this.props.isAdmin() === true ? + (this.props.yslbool===false? + + 删除 +
            }> + this.setModeltrue(true)}> + : "" ) diff --git a/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js b/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js index 92a4832db..d45b7d60f 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js @@ -215,14 +215,14 @@ class GraduateTaskItem extends Component{
            { - this.props.isAdmin?{discussMessage.name}:"" + className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}:"" } { - this.props.isStudent? {discussMessage.name}:"" + className="fl mt3 font-16 font-bd color-dark maxwidth580">{discussMessage.name}:"" } { @@ -280,7 +280,7 @@ class GraduateTaskItem extends Component{ {this.props.isAdmin?
            - + 设置 @@ -302,7 +302,7 @@ class GraduateTaskItem extends Component{ {item==="提交作品"? - 提交作品 + 提交作品 :""} @@ -310,7 +310,7 @@ class GraduateTaskItem extends Component{ {item==="补交作品"? - 补交作品 + 补交作品 :""} @@ -318,7 +318,7 @@ class GraduateTaskItem extends Component{ {item==="修改作品"? - 修改作品 + 修改作品 :""} diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskDetail.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskDetail.js new file mode 100644 index 000000000..0aff1a1bd --- /dev/null +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskDetail.js @@ -0,0 +1,471 @@ +import React, { Component } from 'react'; + +import {Link} from 'react-router-dom'; +import {Tooltip,Menu} from 'antd'; +import Loadable from 'react-loadable'; +import Loading from '../../../../Loading'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; +import axios from 'axios'; +import HomeworkModal from "../../coursesPublic/HomeworkModal"; +import AccessoryModal from "../../coursesPublic/AccessoryModal"; +import Associationmodel from '../../coursesPublic/Associationmodel'; +import CoursesListType from '../../coursesPublic/CoursesListType'; +import moment from 'moment'; +import "../../css/members.css" +import "../../css/Courses.css" + +import Modals from '../../../modals/Modals'; + + +//毕设描述 +const GraduationTasksquestions= Loadable({ + loader: () => import('./GraduationTaskssettingquestions'), + loading: Loading, +}) +//毕设任务设置 +const GraduationTaskssetting=Loadable({ + loader: () => import('./GraduationTaskssetting'), + loading: Loading, +}) +//毕设任务列表 +const GraduationTaskslist=Loadable({ + loader: () => import('./GraduationTaskssettinglist'), + loading: Loading, +}) + +class GraduationTaskDetail extends Component{ + constructor(props){ + super(props); + this.state={ + modalname:undefined, + visible:false, + Topval:undefined, + starttime:undefined, + starttimes:undefined, + typs:undefined, + endtime:undefined, + Cancelname:undefined, + Savesname:undefined, + Cancel:undefined, + Saves:undefined, + Topvalright:undefined, + Botvalleft:undefined, + course_groupslist:undefined, + course_groups:undefined, + questionslist:undefined, + tab:"list", + visibles:undefined, + Modalstype:undefined, + Modalstopval:undefined, + ModalCancel:undefined, + ModalSave:undefined + } + } + componentDidMount(){ + this.getdatas() + } + getdatas=()=>{ + const task_Id = this.props.match.params.task_Id; + let url="/graduation_tasks/"+task_Id+".json"; + + axios.get(url).then((result)=>{ + if(result.status===200){ + this.setState({ + questionslist:result.data + }) + + } + }).catch((error)=>{ + console.log(error) + }) + } + + //返回 + goback=()=>{ + // let courseId=this.props.match.params.coursesId; + // let category_id=this.props.match.params.category_id; + // window.location.href="/courses/"+courseId+"/graduation_tasks/"+category_id; + // let courseId = this.props.match.params.coursesId; + // if(courseId===undefined){ + // this.props.history.push("/courses"); + // }else{ + // this.props.history.push(this.props.current_user.first_category_url); + // } + + // this.props.history.goBack() + this.props.history.replace(`/courses/${this.state.questionslist.course_id}/graduation_tasks/${this.state.questionslist.graduation_id}`); + } + //立即发布 + publish=()=>{ + let starttime= this.props.getNowFormatDates(1,1); + let endtime=this.props.getNowFormatDates(2,1); + // this.homeworkstart() + this.setState({ + modalname:"立即发布", + visible:true, + Topval:"学生将立即收到毕设任务", + // Botvalleft:"点击修改", + // Botval:`本操作只对"未发布"的分班有效`, + starttime:moment(moment(new Date())).format("YYYY-MM-DD HH:mm") , + starttimes:this.props.getNowFormatDates(1), + typs:"start", + endtime:endtime, + Cancelname:"暂不发布", + Savesname:"立即发布", + Cancel:this.cancelmodel, + Saves:this.homepublish, + }) + } + // 确定立即发布 + homepublish=(ids,endtime)=>{ + this.cancelmodel(); + let task_Id=this.props.match.params.task_Id; + const cid = this.props.match.params.coursesId; + // let url = `/courses/${cid}/graduation_tasks/publish_task.json`; + + let url="/courses/"+cid+"/graduation_tasks/publish_task.json" + axios.post(url,{ + task_ids:[task_Id], + group_ids: this.state.course_groupslist, + end_time:endtime, + }).then((response)=>{ + if (response.data.status == 0) { + this.getdatas() + this.props.showNotification(response.data.message); + + this.setState({ + // Modalstopval:response.data.message, + // ModalSave:this.cancelmodel, + // Loadtype:true, + course_groupslist:[], + checkAllValue:false + }) + } + }).catch((error)=>{ + + }) + } + + // 刷新 + resetList=()=>{ + this.getdatas(); + this.child && this.child.searchValue(); + } + + // 立即截止 + end=()=>{ + // this.homeworkstart() + this.setState({ + modalname:"立即截止", + visible:true, + Topval:"学生将不能再提交作品", + // Botvalleft:"暂不截止", + // Botval:`本操作只对"提交中"的分班有效`, + Cancelname:"暂不截止", + Savesname:"立即截止", + Cancel:this.cancelmodel, + Saves:this.coursetaskend, + typs:"end", + }) + } + coursetaskend=()=>{ + const coursesId = this.props.match.params.coursesId; + const task_Id = this.props.match.params.task_Id; + + let url = `/courses/${coursesId}/graduation_tasks/end_task.json`; + axios.post(url,{ + task_ids:[task_Id], + group_ids: this.state.course_groupslist, + }).then((response)=>{ + if (response.data.status == 0) { + this.props.showNotification(response.data.message); + this.cancelmodel(); + this.getdatas(); + this.child && this.child.reInit(); + } + + }).catch((error)=>{ + + }) + } + // 取消 + cancelmodel=()=>{ + debugger + this.setState({ + Modalstype:false, + Loadtype:false, + visible:false, + Modulationtype:false, + Allocationtype:false, + Modalstopval:"", + ModalCancel:"", + ModalSave:"", + }) + } + + getcourse_groupslist=(id)=>{ + this.setState({ + course_groupslist:id + }) + } + + setTab = (tab) =>{ + this.setState({ + tab + }) + } + + // 关联项目 + AssociationItems=()=>{ + this.setState({ + visibles:true + }) + } + Cancel=()=>{ + this.setState({ + visibles:false + }) + } + // 取消关联 + cannelAssociation=()=>{ + this.setState({ + Modalstype:true, + Modalstopval:"确定要取消该项目关联?", + ModalCancel:this.cannerassocition, + ModalSave:this.savetassociton + }) + } + savetassociton=()=>{ + this.cannerassocition(); + let {questionslist}=this.state; + let url = "/graduation_tasks/"+questionslist.task_id+"/graduation_works/cancel_relate_project.json"; + console.log(url) + axios.get(url).then((result)=>{ + if(result.data.status===0){ + this.resetList(); + } + }).catch((error)=>{ + console.log(error) + }) + + } + cannerassocition=()=>{ + this.setState({ + Modalstype:false, + Modalstopval:"", + ModalCancel:"", + ModalSave:"", + loadtype:false, + visibles:false + }) + } + // 补交附件 + handaccessory=()=>{ + // let {taskslistdata}=this.state; + // let courseId=this.props.match.params.coursesId; + // + // let url="/courses/"+courseId+"/graduation_tasks/"+taskslistdata.work_id+"/appraise" + // + // window.location.href=url; + this.setState({ + avisible:true + }) + } + Cancelvisible=()=>{ + this.setState({ + avisible:false + }) + } + + + bindRef = ref => { this.child = ref } ; + render(){ + + let courseId=this.props.match.params.coursesId; + let category_id=this.props.match.params.category_id; + let task_Id=this.props.match.params.task_Id; + let { + questionslist , + tab , + visibles , + Modalstype, + Modalstopval, + ModalCancel, + ModalSave + } = this.state + + const commom = { + setTab:this.setTab + } + return( +
            + { + questionslist && +
            + this.getcourse_groupslist(id)} + /> + {/*关联项目*/} + {visibles===true? + this.Cancel()} + taskid={ questionslist && questionslist.task_id } + funlist={this.resetList} + /> + :""} + + {this.state.avisible===true?:""} + {/*提示*/} + +

            + {questionslist.course_name} + > + {questionslist.graduation_name} + > + 任务详情 +

            +
            +

            + {questionslist.task_name} +

            + + 返回 +
            +
            +
            + + 任务列表 + 毕设描述 + 设置 + + {/*导出成绩*/} + {/*{this.props.isAdmin()?导出成绩:""}*/} + {/*{this.props.isAdmin()?导出作品附件:""}*/} + + + {this.props.isAdmin()?
          • + 导出 + +
          • :""} + {questionslist.work_status===undefined||questionslist.work_status===null||questionslist.work_status.length===0?"":questionslist.work_status.map((item,key)=>{ + return( + + {item==="提交作品"?提交作品:""} + {item==="补交作品"?补交作品:""} + {item==="修改作品"?修改作品:""} + {item==="查看作品"?查看作品 :""} + {item==="创建项目"?创建项目:""} + {item==="关联项目"?关联项目:""} + {item==="取消关联"?取消关联:""} + {item==="补交附件"?补交附件:""} + + + ) + })} + + {/*项目在线质量检测*/} + { this.props.isAdmin() ? questionslist.status===1 ? { this.end()} }>立即截止 : "" : "" } + { this.props.isAdmin() ? questionslist.status===0 ? { this.publish()} }>立即发布 : "" : "" } + + { this.props.isAdmin() ? 编辑任务 : "" } +
            +
            + + + () + } + > + + () + } + > + + () + }> + + +
            + } + +
            + ) + } +} +// CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC)) +export default (GraduationTaskDetail) ; \ No newline at end of file diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js index c527824c5..35d9cdad2 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js @@ -2,7 +2,7 @@ import React,{Component} from "React"; import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal,Spin,Tooltip} from "antd"; import {Link} from 'react-router-dom'; import TPMMDEditor from '../../../tpm/challengesnew/TPMMDEditor'; -import { WordsBtn,getUrl ,bytesToSize,getImageUrl,appendFileSizeToUploadFileAll} from 'educoder'; +import { WordsBtn,getUrl ,bytesToSize,getImageUrl,appendFileSizeToUploadFileAll,appendFileSizeToUploadFile} from 'educoder'; import axios from 'axios'; import Modals from '../../../modals/Modals'; const Search = Input.Search; @@ -49,13 +49,23 @@ class GraduationTasksSubmitedit extends Component{ if(result){ console.log(result.data.description); - + const fileList = result.data.attachments.map(item => { + return { + id: item.id, + uid: item.id, + name: appendFileSizeToUploadFile(item), + url: item.url, + filesize: item.filesize, + status: 'done' + } + }) this.setState({ workslist:result.data, attachments:result.data.attachments, selectmemberslist:result.data.members, selectobjct:result.data.members, description:result.data.description, + fileList:fileList }) if(result.data.task_type===1){ @@ -134,18 +144,7 @@ class GraduationTasksSubmitedit extends Component{ } } - onAttachmentRemoves = (file) => { - if(!file.percent || file.percent == 100){ - this.setState({ - Modalstype:true, - Modalstopval:'确定要删除这个附件吗?', - ModalSave: ()=>this.deleteAttachments(file), - ModalCancel:this.cancelAttachment - }) - return false; - } - } cancelAttachment=()=>{ this.setState({ Modalstype:false, @@ -155,49 +154,7 @@ class GraduationTasksSubmitedit extends Component{ }) } - deleteAttachments = (id) => { - - let {attachments,fileList}=this.state; - - const url = `/attachments/${id}.json` - axios.delete(url, { - }) - .then((response) => { - if (response.data) { - // const { status } = response.data; - if (response.data.status === 0) { - console.log('--- success') - let newattachments=attachments; - - for(var i=0; i { - const index = state.fileList.indexOf(id); - const newFileList = state.fileList.slice(); - newFileList.splice(index, 1); - return { - fileList: newFileList - }; - }); - } - } - }) - .catch(function (error) { - console.log(error); - }); - - } deleteAttachment = (file) => { if(!file.percent || file.percent == 100){ let {attachments,fileList}=this.state; @@ -539,7 +496,8 @@ class GraduationTasksSubmitedit extends Component{ Modalstype,Modalstopval,ModalCancel,ModalSave,memberslist,task_status,selectmemberslist,shixunsreplace} =this.state; let courseId=this.props.match.params.coursesId; - let category_id=this.props.match.params.category_id; + let task_Id=this.props.match.params.coursesId; + // let category_id=this.props.match.params.category_id; let work_Id=this.props.match.params.work_Id const uploadProps = { width: 600, @@ -613,7 +571,7 @@ class GraduationTasksSubmitedit extends Component{ {/*>*/} 毕设任务 > - 任务详情 + 任务详情 > {/**/} {/*{workslist&&workslist.task_name}*/} @@ -623,7 +581,7 @@ class GraduationTasksSubmitedit extends Component{

            -

            {workslist&&workslist.task_name}

            +

            { workslist && workslist.task_name }

            返回
            @@ -672,34 +630,34 @@ class GraduationTasksSubmitedit extends Component{ - {attachments&&attachments.map((item,key)=>{ - - return( -
            - - - - - {item.title} - - - - {item.filesize} - - - {item.delete===true? - this.onAttachmentRemoves(item.id)} - aria-hidden="true"> - :""} -
            - ) - })} + {/*{attachments&&attachments.map((item,key)=>{*/} + + {/*return(*/} + {/*
            */} + {/**/} + {/**/} + {/**/} + {/**/} + {/*{item.title}*/} + + {/**/} + {/**/} + {/*{item.filesize}*/} + + {/**/} + {/*{item.delete===true?*/} + {/*this.onAttachmentRemoves(item.id)}*/} + {/*aria-hidden="true">*/} + {/*:""}*/} + {/*
            */} + {/*)*/} + {/*})}*/} {/* -
            -
            - -

            - {coursename} - > - 毕设任务 - > - - {/*{taskname===""?"":*/} - {/**/} - {/*{taskname}*/} - {/*>*/} - {/**/} - {/*}*/} - - 任务详情 -

            - -
            -

            - {taskname} -

            - - 返回 -
            - - -
            -
            - - 任务列表 - 毕设描述 - 设置 - - {/*导出*/} - - {this.props.isAdmin()?
          • - 导出 - -
          • :""} - - {/*{this.props.isAdmin()?导出成绩:""}*/} - {/*{this.props.isAdmin()?导出作品附件:""}*/} - {/*项目在线质量检测*/} - {this.props.isAdmin()?settingdata.status===1? { this.end()} }>立即截止:"":""} - {this.props.isAdmin()?settingdata.status===0? { this.publish()} }>立即发布:"":""} - {this.props.isAdmin()?编辑任务:""} -
            -
            - - - { !flagPageEdit && this.props.isAdmin() === true ? @@ -1175,7 +1018,7 @@ class GraduationTaskssettingapp extends Component{ -
            +
            发布时间: @@ -1213,7 +1056,7 @@ class GraduationTaskssettingapp extends Component{ {this.state.publishTimetypesval}
            :""} -
            +
            截止时间: @@ -1306,11 +1149,6 @@ class GraduationTaskssettingapp extends Component{
            - {/*
            */} - {/*
            项目质量检测
            */} - - - {/*
            */}
            评分设置
            @@ -1437,14 +1275,8 @@ class GraduationTaskssettingapp extends Component{ {/*取消*/} 取消
            :"":""} -
            -
            - - +
            :""} - - - ) diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js index 7e60b995c..acfcbaa63 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js @@ -1,7 +1,7 @@ import React,{Component} from "React"; import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal,Pagination, Table, Divider, Tag,Tooltip} from "antd"; import {Link} from 'react-router-dom'; -import { getImageUrl,WordsBtn } from 'educoder'; +import { getImageUrl , NoneData } from 'educoder'; import axios from 'axios'; import moment from 'moment'; import HomeworkModal from "../../coursesPublic/HomeworkModal"; @@ -13,6 +13,7 @@ import AllocationModal from "../../coursesPublic/AllocationModal"; import Associationmodel from '../../coursesPublic/Associationmodel'; import AccessoryModal from "../../coursesPublic/AccessoryModal"; + const CheckboxGroup = Checkbox.Group; const Search = Input.Search; const qs = require('qs'); @@ -54,8 +55,18 @@ class GraduationTaskssettinglist extends Component{ } componentDidMount(){ + let tab = this.props.tab; + this.props.setTab && this.props.setTab(tab); + + let{teacher_comment,task_status,course_group,cross_comment,order,b_order,search}=this.state; this.seacthdata(teacher_comment,task_status,course_group,cross_comment,order,b_order,search,this.state.page); + + try{ + this.props.triggerRef(this) + }catch(e){ + + } } goback=()=>{ @@ -70,6 +81,15 @@ class GraduationTaskssettinglist extends Component{ this.props.history.replace(`/courses/${this.state.taskslistdata.course_id}/graduation_tasks/${this.state.taskslistdata.graduation_id}`); } + reInit=()=>{ + this.setState({ + course_groupslist:[], + checkAllValue:false + }) + let {teacher_comment, task_status, course_group, cross_comment, order, b_order, search} = this.state; + this.seacthdata(teacher_comment, task_status, course_group, cross_comment, order, b_order, search,this.state.page); + } + seacthdata=(teacher_comment,task_status,course_group,cross_comment,order,b_order,search,pages)=>{ let{page,limit}=this.state; // console.log(teacher_comment,task_status,course_group,cross_comment,order,b_order,search) @@ -86,7 +106,7 @@ class GraduationTaskssettinglist extends Component{ order:order===null?undefined:order, b_order:b_order===null?undefined:b_order, search:search===null?undefined:search, - page:pages===null?undefined:pages, + page:pages===null?undefined:page, limit:20, }, paramsSerializer: function(params) { @@ -635,6 +655,8 @@ class GraduationTaskssettinglist extends Component{ /// 确认是否下载 confirmysl(url){ + debugger; + console.log(1); let {teacher_comment, task_status, course_group, cross_comment, order, b_order, search,page} =this.state; let params ={ @@ -837,36 +859,22 @@ class GraduationTaskssettinglist extends Component{
            {this.props.isAdmin()?operation.map((tag,key) => { return( -
            - {/*调整学生最终成绩
            */} - {/*其它历史评分将全部失效:""}>*/} - - {/*{tag.name==="评阅"?tag.status===0?"--":*/} - {/*{tag.name}*/} - {/**/} - {/*:*/} - {/*this.showModulationtype(tag.id):tag.name==="分配"?()=>this.showAllocationModal(tag.id):""}>*/} - {/*{tag.status===0?"":tag.name}*/} - {/**/} - {/*}*/} - - {/*
            */} - 调整学生最终成绩
            - 其它历史评分将全部失效:""}> - - {tag.name==="评阅"? - {tag.name} - - : - this.showModulationtype(tag.id):tag.name==="分配"?()=>this.showAllocationModal(tag.id):""}> - {tag.name} - - } - -
            -
            + + { + tag.name && + 调整学生最终成绩
            其它历史评分将全部失效:""}> + {tag.name==="评阅"? + {tag.name} + + : + this.showModulationtype(tag.id):tag.name==="分配"?()=>this.showAllocationModal(tag.id):""}> + {tag.name} + + } +
            + } +
            ) }):""} { @@ -963,9 +971,6 @@ class GraduationTaskssettinglist extends Component{ text-overflow: ellipsis; white-space: nowrap; } - .linbox{ - height: 26px; - } .ant-table-tbody>tr>td, .ant-table-thead>tr>th{ padding: 16px 10px } @@ -1090,99 +1095,12 @@ class GraduationTaskssettinglist extends Component{ /> - {taskslistdata&&taskslistdata? + { taskslistdata && taskslistdata ? // 教师列表 - this.props.isAdmin()?
            -
            - -

            - {taskslistdata.course_name} - > - {taskslistdata.graduation_name} - > - 任务详情 -

            - -
            -

            {taskslistdata.task_name}

            - - 返回 -
            - - -
            -
            - {/*导出成绩*/} - {/*导出作品附件*/} - 任务列表 - 毕设描述 - 设置 - - {/*编辑任务*/} - {/*立即截止*/} - - - {/*导出作品附件*/} - - {this.props.isAdmin()?
          • - 导出 - -
          • :""} - - {/*项目在线质量检测*/} - {taskslistdata.status===1? { this.end()} }>立即截止:""} - {taskslistdata.status===0? { this.publish()} }>立即发布:""} - 编辑任务 - -
            -
            - - - + this.props.isAdmin() ?
            -
            - {/*提示*/} - {/**/} - -
            - - - - : + : // 学生列表 this.props.isStudent()||this.props.isNotMember()? -
            -
            - -

            - {taskslistdata.course_name} - > - {taskslistdata.graduation_name} - > - 任务详情 -

            - -
            - -
            -
            - - 任务列表 - 毕设描述 - 设置 - - - {taskslistdata.work_status===undefined||taskslistdata.work_status===null||taskslistdata.work_status.length===0?"":taskslistdata.work_status.map((item,key)=>{ - return( - - {item==="提交作品"?提交作品:""} - {item==="补交作品"?补交作品:""} - {item==="修改作品"?修改作品:""} - {item==="查看作品"?查看作品 :""} - {item==="创建项目"?创建项目:""} - {item==="关联项目"?关联项目:""} - {item==="取消关联"?取消关联:""} - {item==="补交附件"?补交附件:""} - - - ) - })} - - {/*补交附件*/} - {/*编辑任务*/} - {/*立即截止*/} - {/*导出作品附件*/} - {/*导出成绩*/} - -
            -
            - -
            - {this.props.isNotMember()?
              + {this.props.isNotMember()?
              • 教师评阅: @@ -1554,7 +1406,6 @@ class GraduationTaskssettinglist extends Component{
                - {this.props.isAdmin()===true?
                @@ -1576,8 +1427,6 @@ class GraduationTaskssettinglist extends Component{
                :""} - - {this.props.isStudent()===true?
                @@ -1595,12 +1444,7 @@ class GraduationTaskssettinglist extends Component{ }
                :""} - - -
            - - { JSON.stringify(data) === "[]" ? @@ -1652,12 +1496,6 @@ class GraduationTaskssettinglist extends Component{ : "" }
            - - -
            -
            - - :"" :""} diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js index c40c9aa54..06ed1eaa1 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js @@ -32,9 +32,21 @@ class GraduationTasksquestions extends Component{ } componentDidMount(){ + let tab = this.props.tab; + this.props.setTab && this.props.setTab(tab); + + this.getdatas(); + try{ + this.props.triggerRef(this) + }catch(e){ + + } + } - this.getdatas() + reInit=()=>{ + this.getdatas(); } + getdatas=()=>{ const task_Id = this.props.match.params.task_Id; let url="/graduation_tasks/"+task_Id+".json"; @@ -44,7 +56,6 @@ class GraduationTasksquestions extends Component{ this.setState({ questionslist:result.data }) - } }).catch((error)=>{ console.log(error) @@ -202,6 +213,8 @@ class GraduationTasksquestions extends Component{ /// 确认是否下载 confirmysl(url){ + debugger; + console.log(2); axios.get(url + '?export=true').then((response) => { if(response === undefined){ return @@ -295,93 +308,8 @@ class GraduationTasksquestions extends Component{ modaltype={this.state.modaltype} getcourse_groupslist={(id) => this.getcourse_groupslist(id)} /> - {questionslist&&questionslist?
            - -

            - {questionslist.course_name} - > - {questionslist.graduation_name} - > - 任务详情 -

            - -
            -

            - {questionslist.task_name} -

            - - 返回 -
            - - -
            -
            - - 任务列表 - 毕设描述 - 设置 - - {/*导出成绩*/} - {/*{this.props.isAdmin()?导出成绩:""}*/} - {/*{this.props.isAdmin()?导出作品附件:""}*/} - - - {this.props.isAdmin()?
          • - 导出 - -
          • :""} - - {/*项目在线质量检测*/} - {this.props.isAdmin()?questionslist.status===1? { this.end()} }>立即截止:"":""} - {this.props.isAdmin()?questionslist.status===0? { this.publish()} }>立即发布:"":""} - {this.props.isAdmin()?编辑任务:""} -
            -
            - - -

            @@ -397,22 +325,6 @@ class GraduationTasksquestions extends Component{ }

            - {/*{questionslist&&questionslist.attachments.map((item,key)=>{*/} - {/*return(*/} - {/*
            */} - {/**/} - {/**/} - {/**/} - {/**/} - {/*{item.title}*/} - {/**/} - {/*{item.filesize}*/} - - {/*
            */} - {/*)*/} - - {/*})}*/}
            diff --git a/public/react/src/modules/courses/graduation/tasks/index.js b/public/react/src/modules/courses/graduation/tasks/index.js index 804533b0c..ed52d5cbc 100644 --- a/public/react/src/modules/courses/graduation/tasks/index.js +++ b/public/react/src/modules/courses/graduation/tasks/index.js @@ -469,7 +469,9 @@ class GraduationTasks extends Component{ checkAllValue:false }) this.publishcanner(); - this.useBankSuccess(); + debugger + let {search,page,order} = this.state + this.fetchAll(search,page,order); } }).catch((error)=>{ @@ -565,6 +567,12 @@ class GraduationTasks extends Component{ let {search,page,order,all_count} = this.state; this.fetchAll(search,page,order,all_count) + this.setState({ + checkBoxValues:object_ids + }) + + // 立即发布 + this.publish(); } getcourse_groupslist=(id)=>{ diff --git a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js index 20e03d069..ba2ab53d9 100644 --- a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js +++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js @@ -449,7 +449,7 @@ class GraduateTopicNew extends Component{ rules: [{ required: true, message: '请输入选题简介', }, { - max: 10000, message: '最大限制为10000个字符', + max: 5000, message: '最大限制为5000个字符', }], })( { + this.setState({ + teacherList:result.data.teacher_list, + topic_property_first:result.data.topic_property_first, + topic_property_second:result.data.topic_property_second, + topic_repeat:result.data.topic_repeat, + topic_source:result.data.topic_source, + topic_type:result.data.topic_type, + addonAfter:parseInt(result.data.selected_data.name.length) + }) + this.props.form.setFieldsValue({ + tea_id:result.data.selected_data.tea_id, + name:result.data.selected_data.name, + city: [result.data.selected_data.province,result.data.selected_data.city], + topic_type:result.data.selected_data.topic_type || undefined, + topic_source:result.data.selected_data.topic_source || undefined, + topic_property_first:result.data.selected_data.topic_property_first || undefined, + topic_property_second:result.data.selected_data.topic_property_second || undefined, + source_unit:result.data.selected_data.source_unit, + topic_repeat:result.data.selected_data.topic_repeat || undefined + }); + this.mdRef.current.setValue(result.data.selected_data.description) + const _fileList = result.data.attachments.map(item => { + return { + id: item.id, + uid: item.id, + name: item.title, + url: item.url, + status: 'done' + } + }) + this.setState({ fileList: _fileList, cityDefaultValue: [result.data.selected_data.province,result.data.selected_data.city] }) + } + //init新建信息 + initNewInfo=(result)=>{ + this.setState({ + teacherList:result.data.teacher_list, + topic_property_first:result.data.topic_property_first, + topic_property_second:result.data.topic_property_second, + topic_repeat:result.data.topic_repeat, + topic_source:result.data.topic_source, + topic_type:result.data.topic_type + }) + + this.props.form.setFieldsValue({ + tea_id:this.props.current_user && this.props.current_user.user_id + }) + } + + // 附件相关 START + handleChange = (info) => { + if (info.file.status === 'done' || info.file.status === 'uploading') { + let contentFileList = info.fileList; + // this.setState({ fileList: appendFileSizeToUploadFileAll(contentFileList)}); + // let list = appendFileSizeToUploadFileAll(contentFileList); + // let arr = list.map(item=>{ + // return ( item.response && item.response.id ) + // }) + this.setState({ + fileList:contentFileList + }); + } + } + onAttachmentRemove = (file) => { + this.props.confirm({ + content: '确定要删除这个附件吗?', + onOk: () => { + this.deleteAttachment(file) + }, + onCancel() { + console.log('Cancel'); + }, + }); + return false; + } + deleteAttachment = (file) => { + console.log(file); + let id=file.response ==undefined ? file.id : file.response.id + const url = `/attachments/${id}.json` + axios.delete(url).then((response) => { + if (response.data) { + const { status } = response.data; + if (status == 0) { + console.log('--- success') + + this.setState((state) => { + const index = state.fileList.indexOf(file); + const newFileList = state.fileList.slice(); + newFileList.splice(index, 1); + return { + fileList: newFileList, + }; + }); + } + } + }) + .catch(function (error) { + console.log(error); + }); + } + + changeTopicName=(e)=>{ + // let num= 60 - parseInt(e.target.value.length); + this.setState({ + addonAfter:e.target.value.length + }) + } + + + handleSubmit = (e) => { + e.preventDefault(); + const topicId = this.props.topicId + this.props.form.validateFieldsAndScroll((err, values) => { + if (!err) { + if (topicId !=undefined) { + // 编辑 + // const editTopic = this.editTopic + let attachment_ids = undefined + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response ? item.response.id : item.id + }) + } + const param = { + ...values, + province: values.city==undefined?"":values.city[0], + city: values.city==undefined?"":values.city[1], + } + this.props.editSave && this.props.editSave(param,attachment_ids,topicId); + } else { + // 新建 + let attachment_ids = undefined + if (this.state.fileList) { + attachment_ids = this.state.fileList.map(item => { + return item.response.id + }) + } + const param ={ + ...values, + province: values.city==undefined?"":values.city[0], + city: values.city==undefined?"":values.city[1], + } + this.props.newSubmit && this.props.newSubmit(param,attachment_ids,topicId); + } + } else { + $("html").animate({ scrollTop: $('html').scrollTop() - 100 }) + } + }); + } + + // 附件相关 ------------ END + render(){ + let{ + fileList, + teacherList, + topic_property_first, + topic_property_second, + topic_repeat, + topic_source, + topic_type, + addonAfter, + cityDefaultValue + }=this.state; + const { getFieldDecorator } = this.props.form; + const formItemLayout = { + labelCol: { + xs: { span: 24 }, + // sm: { span: 8 }, + sm: { span: 24 }, + }, + wrapperCol: { + xs: { span: 24 }, + // sm: { span: 16 }, + sm: { span: 24 }, + }, + }; + const uploadProps = { + width: 600, + fileList, + multiple: true, + action: `${getUploadActionUrl()}`, + onChange: this.handleChange, + onRemove: this.onAttachmentRemove, + beforeUpload: (file) => { + const isLt150M = file.size / 1024 / 1024 < 150; + if (!isLt150M) { + //message.error('文件大小必须小于150MB!'); + this.props.define({ + title:'提示', + content:"该文件无法上传。超过文件大小限制(150MB),建议上传到百度云等其它共享工具里,然后再txt文档里给出链接以及共享密码并上传" + }) + return isLt150M; + } + } + }; + let { topicId , teacherName }=this.props; + return( + + +
            + { + teacherName && + + {getFieldDecorator('tea_id', { + rules: [{ + required: true, message: '请选择指导老师' + }], + })( + + )} + + } + + + {getFieldDecorator('name', { + rules: [{ + required: true, message: '请输入选题名称', + }, { + max: 60, message: '最大限制为60个字符', + }], + })( + + )} + +
            + + + +
            + + + {getFieldDecorator('description', { + rules: [{ + required: true, message: '请输入选题简介', + }, { + max: 10000, message: '最大限制为10000个字符', + }], + })( + // initValue={this.editTopic ? this.editTopic.content : ''} + + )} + + + { + getFieldDecorator('file',{ + rules:[{ + required:false + }] + })( + + + (单个文件150M以内) + + ) + } + +
            + + {getFieldDecorator('topic_type', { + rules: [{ + required: false, message: '', + }], + })( + + )} + + + {getFieldDecorator('topic_source', { + rules: [{ + required: false, message: '', + }], + })( + + )} + + + {getFieldDecorator('topic_property_first', { + rules: [{ + required: false, message: '', + }], + })( + + )} + + + {getFieldDecorator('topic_property_second', { + rules: [{ + required: false, message: '', + }], + })( + + )} + +
            +
            + + + + + +
            + + {getFieldDecorator('source_unit', { + rules: [{ + required: false, message: '', + }], + })( + + )} + + + {getFieldDecorator('topic_repeat', { + rules: [{ + required: false, message: '', + }], + })( + + )} + + + {getFieldDecorator('city', { + rules: [{ + initialValue: cityDefaultValue, + type: 'array', + required: false, message: '', + }], + })( + + )} + +
            + + +
            + + 取消 +
            +
            + +
            + ) + } +} + +const WrappedGraduateTopicNewForm = Form.create({ name: 'topicPostWorksNew' })(GraduateTopicNewForm); +// RouteHOC() +export default (WrappedGraduateTopicNewForm); \ No newline at end of file diff --git a/public/react/src/modules/courses/groupjobbank/GroupPackage.js b/public/react/src/modules/courses/groupjobbank/GroupPackage.js index 8014585d1..e0b220202 100644 --- a/public/react/src/modules/courses/groupjobbank/GroupPackage.js +++ b/public/react/src/modules/courses/groupjobbank/GroupPackage.js @@ -1,3 +1,4 @@ + import React, {Component} from "react"; import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; import { @@ -21,7 +22,9 @@ class GroupPackage extends Component { } } - + DownloadOpenPdf=(type,url)=>{ + type===true?window.open(url):window.location.href=url; + } componentDidMount() { console.log("Groupjobquesanswer"); console.log("componentDidMount"); @@ -34,7 +37,6 @@ class GroupPackage extends Component { - } // 获取数据地方 getTrainingjobsetting = () => { @@ -54,9 +56,9 @@ class GroupPackage extends Component { render() { - + let{attachments}=this.props; return ( -
            + ) diff --git a/public/react/src/modules/courses/groupjobbank/GroupPackage2.js b/public/react/src/modules/courses/groupjobbank/GroupPackage2.js index 6a48a51c8..63fae45f8 100644 --- a/public/react/src/modules/courses/groupjobbank/GroupPackage2.js +++ b/public/react/src/modules/courses/groupjobbank/GroupPackage2.js @@ -54,18 +54,59 @@ class GroupPackage extends Component { render() { + let{datas,bool}=this.props; return ( -
            -

            - 分组要求: - 2~ 5(学生提交作品时需要关联同组成员,组内成员作品共享) -

            -

            - 基于项目实施 - (学生必须在本平台创建项目,项目管理员可以提交作品) -

            -
            + bool===true? + +
            + { + datas===undefined?"":datas.min_num===undefined||datas.max_num===undefined?"":datas.min_num===null||datas.max_num===null?"": +

            + 分组要求: + {datas&&datas.min_num}~ {datas&&datas.max_num} 人(学生提交作品时需要关联同组成员,组内成员作品共享) +

            + } + + { + datas===undefined?"":datas.base_on_project===undefined?"": + datas.base_on_project===true? +

            + 基于项目实施 + (学生必须在本平台创建项目,项目管理员可以提交作品) +

            + :datas.base_on_project===false? +

            + 不基于项目 + (无需在平台创建项目,任意小组成员均可以提交作品) +

            + :"" + } + +
            + :
            + { + datas===undefined?"":datas.group_info===undefined?"":datas.group_info.min_number===undefined||datas.group_info.max_number===undefined?"": + datas.group_info.min_number===null||datas.group_info.max_number===null?"": +

            + 分组要求: + {datas&&datas.group_info&&datas.group_info.min_number}~ {datas&&datas.group_info&&datas.group_info.max_number} 人(学生提交作品时需要关联同组成员,组内成员作品共享) +

            + } + { + datas&&datas.group_info&&datas.group_info.base_on_project===1? +

            + 基于项目实施 + (学生必须在本平台创建项目,项目管理员可以提交作品) +

            + :datas&&datas.group_info&&datas.group_info.base_on_project===0? +

            + 不基于项目 + (无需在平台创建项目,任意小组成员均可以提交作品) +

            + :"" + } +
            ) } } diff --git a/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js b/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js index 772752def..39a010006 100644 --- a/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js +++ b/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js @@ -1,5 +1,6 @@ + import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -12,6 +13,9 @@ import { } from "antd"; import './questionbanks.css'; import GroupPackage from "./GroupPackage"; +import AttachmentsList from "../../../common/components/attachment/AttachmentList"; +import NoneData from '../../courses/coursesPublic/NoneData' + import GroupPackage2 from "./GroupPackage2"; @@ -57,20 +61,62 @@ class Groupjobbandetails extends Component { render() { + let{datas}=this.props; return ( -
            +
            - -
            - - - - + { + datas.description===null? + "" + :datas.description==="null"? + "" + : + datas.description===""? + "" + : + + //
            + } + {/*
            */} + {/*{datas.attachments === undefined ? "" : datas.attachments.map((item, key) => {*/} + {/* return (*/} + {/* */} + {/* )*/} + {/*})}*/} + {datas.attachments === undefined ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments=== "" ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments=== null ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments.length === 0 ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : +
            + +
            + } +
            diff --git a/public/react/src/modules/courses/groupjobbank/GroupjobbankPage.js b/public/react/src/modules/courses/groupjobbank/GroupjobbankPage.js index 27827eb28..873c4c1e6 100644 --- a/public/react/src/modules/courses/groupjobbank/GroupjobbankPage.js +++ b/public/react/src/modules/courses/groupjobbank/GroupjobbankPage.js @@ -1,20 +1,26 @@ import React, {Component} from "react"; -import {Link, NavLink} from 'react-router-dom'; -import {WordsBtn, ActionBtn} from 'educoder'; +import {BrowserRouter as Router,Route,Switch,Link, NavLin} from 'react-router-dom'; +import {WordsBtn, ActionBtn,getImageUrl} from 'educoder'; import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Button,Form } from "antd"; import axios from 'axios'; -import { - notification -} from "antd"; -import CoursesListType from '../coursesPublic/CoursesListType'; -import Groupjobbandetails from './Groupjobbandetails'; -import Groupjobquesanswer from './Groupjobquesanswer'; +import BanksMenu from '../../user/usersInfo/banks/banksMenu' +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; import '../css/members.css'; import "../common/formCommon.css"; import '../css/Courses.css'; import '../css/busyWork.css'; import '../poll/pollStyle.css'; - +// 问卷内容 +const Groupjobbandetails = Loadable({ + loader: () => import('./Groupjobbandetails'), + loading: Loading, +}) +// 试卷详情 +const Groupjobquesanswer = Loadable({ + loader: () => import('./Groupjobquesanswer'), + loading: Loading, +}); class GroupjobbankPage extends Component { //分组作业内容详情 constructor(props) { @@ -25,53 +31,25 @@ class GroupjobbankPage extends Component { workid:1, isSpin:false, datas:[], + visible:false, + banksMenu:undefined } - } - //切换tab - ChangeTab = (e) => { - // console.log(e); - this.setState({ - tab: e - }) - try { - var currenturl = window.location.href; - var newUrl = (currenturl.split("?"))[0]; - window.history.pushState('','',newUrl+'?tab='+e); - }catch (e) { - console.log(e); - console.log("44"); - } + componentDidMount() { + this.getonedata(); } - - componentDidMount() { - // console.log("父组件加载框"); - const query = this.props.location.search; - const type = query.split('?tab='); - // let sum = [] - // sum.push(type[1]) - // console.log("componentDidMountcomponentDidMount"); - // console.log(type); - this.setState({ - tab: type[1], - }) - let querys = this.props.location.pathname; - const types = querys.split('/'); - // console.log(types); - this.setState({ - shixuntypes: types[3] - }) + getonedata=()=>{ if( this.props.match.params.workid){ this.setState({ workid: this.props.match.params.workid, }) } this.getdata(this.props.match.params.workid); - } - ///获取数据的地方 + }; + //获取数据的地方 getdata=(workid)=>{ var workids= workid; if(workids){ @@ -88,8 +66,36 @@ class GroupjobbankPage extends Component { if(response){ if(response.data){ this.setState({ - datas:response.data.informs, + datas:response.data, }) + try { + const crumbData={ + title:response && response.data && response.data.name, + is_public:response && response.data && response.data.is_public, + crumbArray:[ + {content:'详情'} + ] + }; + const menuData={ + tab:'0',//tab选中的index + menuArray:[//tab以及tab路由 + {to:`/banks/group/${workids}/${this.props.match.params.type}?tab=0`,content:'内容详情'}, + {to:`/banks/group/${workids}/${this.props.match.params.type}/answer?tab=1`,content:'参考答案'} + ], + category:'group',//毕设选题 + tos:`/banks/group/${workids}/edit/${this.props.match.params.type}?tab=0`, + id:workids, + is_public:response && response.data && response.data.is_public, + type:this.props.match.params.type, + authorize:response && response.data && response.data.authorize, + } + this.setState({ + banksMenu:menuData + }) + this.props.initPublic(crumbData,response.data); + }catch (e) { + + } }else { this.setState({ datas:[], @@ -113,63 +119,55 @@ class GroupjobbankPage extends Component { isSpin:false, }) }); - } - - - bindRef = ref => { this.child = ref } -///////////////教师截止 + }; + // initPublic = (crumbData,menuData) =>{ + // this.setState({ + // banksMenu:menuData + // }) + // this.props.initPublic(crumbData); + // } render() { - let {tab} = this.state; - - const isAdmin = this.props.isAdmin(); - // console.log(119) - + let {tab,datas,visible} = this.state; + let{ + banksMenu + }=this.state + // + // const common={ + // initPublic:this.initPublic, + // } return ( -
            - - -
            - -
            -

            - 题库 - > - 详情 -

            -
            -
            -

            - MySQL数据库编程开发实训(基础篇) -

            - -
            - - - - {parseInt(tab) === 0 ? :""} - {parseInt(tab) === 1 ? :""} - -
            -
            + +
            + { + banksMenu && + + } + + { + return () + } + }> + { + return () + } + }> + +
            +
            ) } + + } export default GroupjobbankPage; - diff --git a/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js b/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js index c6a0f787f..3d41ccb79 100644 --- a/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js +++ b/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js @@ -1,5 +1,6 @@ + import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -10,8 +11,10 @@ import { Tooltip, notification, } from "antd"; +import AttachmentsList from '../../../common/components/attachment/AttachmentList' import GroupPackage from './GroupPackage'; import GroupPackage2 from './GroupPackage2'; +import NoneData from '../../courses/coursesPublic/NoneData' import './questionbanks.css'; class Groupjobquesanswer extends Component { @@ -56,23 +59,54 @@ class Groupjobquesanswer extends Component { render() { - + let{datas}=this.props; return ( -
            +
            - -
            - - - - + { + datas.reference_answer===null? + "" + :datas.reference_answer==="null"? + "" : + datas.reference_answer===""? + "" + : + + } + + {datas.reference_attachments === undefined ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments === "" ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments === null ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments.length === 0 ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : +
            + +
            + }
            - -
            ) diff --git a/public/react/src/modules/courses/groupjobbank/questionbanks.css b/public/react/src/modules/courses/groupjobbank/questionbanks.css index aae0c979f..1c4d86769 100644 --- a/public/react/src/modules/courses/groupjobbank/questionbanks.css +++ b/public/react/src/modules/courses/groupjobbank/questionbanks.css @@ -2,9 +2,11 @@ padding-top: 30px !important; padding-right: 30px !important; padding-left: 30px !important; + min-height: 500px !important; } .yslquesHeigth{ - min-height: 500px !important; + width: 100% !important; + } .yslquesmarkdowntext{ @@ -30,6 +32,7 @@ } .ml47text{ margin-left: 17px; + margin-top: 33px; padding-bottom: 37px; } .ysltextcolor99999{ @@ -38,4 +41,10 @@ } .yslahover { color: #999999 ; +} +.mt24{ + margin-top: 24px !important ; +} +.pd30{ + margin-bottom: 30px; } \ No newline at end of file diff --git a/public/react/src/modules/courses/members/CourseGroupChooser.js b/public/react/src/modules/courses/members/CourseGroupChooser.js index ba9c64bb1..125f10b51 100644 --- a/public/react/src/modules/courses/members/CourseGroupChooser.js +++ b/public/react/src/modules/courses/members/CourseGroupChooser.js @@ -41,7 +41,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde console.log('arg_course_groups', arg_course_groups) - const urlStyle = {"lef":"tunset", minWidth: '262px'}; + const urlStyle = {"left":"unset", minWidth: '262px'}; if (alwaysShow == true) { urlStyle.display = 'block' } @@ -89,7 +89,7 @@ function CourseGroupChooser({ course_groups, isAdminOrCreator = true, item, inde

            trigger('groupAdd')} - >添加分班... + >添加分班

            ) diff --git a/public/react/src/modules/courses/members/modal/AddStudentModal.js b/public/react/src/modules/courses/members/modal/AddStudentModal.js index 9113ba6ab..5816021a5 100644 --- a/public/react/src/modules/courses/members/modal/AddStudentModal.js +++ b/public/react/src/modules/courses/members/modal/AddStudentModal.js @@ -213,18 +213,18 @@ class AddStudentModal extends Component{ {/* */} -

            +

            - - - - + {'姓名'} + {'学号'} + {'单位'} + {''}

            { loading || users.length ?
            {/* https://github.com/CassetteRocks/react-infinite-scroller/issues/70 */} -
            +
            - - 12 }> - - + : } - - 12 }> - - + + {candidate.student_id || ' '} - - - + {candidate.school_name} + {candidate.added ? '已加入' : ''}

            ) }) } diff --git a/public/react/src/modules/courses/members/modal/AddTeacherModal.js b/public/react/src/modules/courses/members/modal/AddTeacherModal.js index b397f7838..7aa7d1114 100644 --- a/public/react/src/modules/courses/members/modal/AddTeacherModal.js +++ b/public/react/src/modules/courses/members/modal/AddTeacherModal.js @@ -109,6 +109,11 @@ class AddTeacherModal extends Component{ checkBoxValues: [] }) } + this.setState({ + name:undefined, + graduationGroup:undefined, + courseGroup:undefined + }) } onSendOk = () => { @@ -257,12 +262,12 @@ class AddTeacherModal extends Component{ {/* graduation_groups && !!graduation_groups.length */} -

            +

            - - - - + {'姓名'} + {'昵称'} + {'单位'} + {''}

            { loading || candidates.length ?
            @@ -281,26 +286,17 @@ class AddTeacherModal extends Component{ { candidates && candidates.map( candidate => { return (

            - - - {/* "color":"#4c4c4c" */} - 12 }> - - + + + {candidate.name} + + + {candidate.nickname} - - 12 }> - - + + {candidate.school_name} - - - + {candidate.added ? '已加入' : ''}

            ) }) } diff --git a/public/react/src/modules/courses/members/modal/CourseGroupChooserModal.js b/public/react/src/modules/courses/members/modal/CourseGroupChooserModal.js index 2f08d08a1..f5365433d 100644 --- a/public/react/src/modules/courses/members/modal/CourseGroupChooserModal.js +++ b/public/react/src/modules/courses/members/modal/CourseGroupChooserModal.js @@ -65,22 +65,34 @@ function CourseGroupChooserModal({ course_groups = [], isAdminOrCreator, item, i className="courseGroupChooserModal" > {/* */} diff --git a/public/react/src/modules/courses/members/studentsList.js b/public/react/src/modules/courses/members/studentsList.js index 47d387e5d..76e0a7b7c 100644 --- a/public/react/src/modules/courses/members/studentsList.js +++ b/public/react/src/modules/courses/members/studentsList.js @@ -7,7 +7,7 @@ import CourseLayoutcomponent from '../common/CourseLayoutComponent' import Titlesearchsection from '../common/titleSearch/TitleSearchSection' import ColorCountText from '../common/titleSearch/ColorCountText' -import { WordsBtn, trigger, on, off, getUrl, downloadFile } from 'educoder' +import { WordsBtn, trigger, on, off, getUrl, downloadFile , sortDirections } from 'educoder' import Modals from "../../modals/Modals"; import axios from 'axios' import _ from 'lodash' @@ -17,8 +17,9 @@ import CreateGroupByImportModal from './modal/CreateGroupByImportModal' const Search =Input.Search; -const buildColumns = (that) => { - const { course_groups } = that.state +const buildColumns = (that,isParent) => { + const { course_groups , sortedInfo } = that.state + let showSorter = isParent==true const columns=[{ title: '序号', dataIndex: 'id', @@ -59,6 +60,9 @@ const buildColumns = (that) => { align:'center', width:"10%", className:"color-grey-6", + sorter: true, + sortDirections: sortDirections, + sortOrder: sortedInfo.columnKey === 'student_id' && sortedInfo.order, render: (student_id, record) => { return 10 ? student_id : ''} style={{maxWidth: '160px'}} >{student_id} @@ -71,7 +75,10 @@ const buildColumns = (that) => { key: 'course_group_name', align:'center', width:"40%", - className:"color-grey-6" + className:"color-grey-6", + sorter:showSorter, + sortDirections: sortDirections, + sortOrder: sortedInfo.columnKey === 'course_group_name' && sortedInfo.order, }) } const isAdminOrStudent = that.props.isAdminOrStudent() @@ -124,6 +131,7 @@ class studentsList extends Component{ isSpin:false, DownloadType:false, DownloadMessageval:undefined, + sortedInfo: {order:'ascend',columnKey: 'student_id'} } } /// 确认是否下载 @@ -319,8 +327,19 @@ class studentsList extends Component{ this.setState({ page: argPage }) } let page = argPage || this.state.page - let { order, searchValue }=this.state - let url=`/courses/${id}/students.json?order=${order}&page=${page}&limit=20&course_group_id=${course_group_id}`; + let { searchValue , sortedInfo }=this.state + let order = 1; + if (sortedInfo.columnKey == 'student_id') { + order = 1; + } else if (sortedInfo.columnKey == 'course_group_name') { + order = 2; + } + let sort = 'desc'; + if (sortedInfo.order == 'ascend') { + sort = 'asc' + } + + let url=`/courses/${id}/students.json?order=${order}&sort=${sort}&page=${page}&limit=20&course_group_id=${course_group_id}`; if(!!searchValue){ url+='&search='+searchValue; } @@ -355,12 +374,12 @@ class studentsList extends Component{ searchValue: e.target.value }) - if (this.timeoutHandler) { - clearTimeout(this.timeoutHandler) - } - this.timeoutHandler = setTimeout(() => { - this.fetchAll(1) - }, 1200) + // if (this.timeoutHandler) { + // clearTimeout(this.timeoutHandler) + // } + // this.timeoutHandler = setTimeout(() => { + // this.fetchAll(1) + // }, 1200) } onSortTypeChange = (order) => { this.setState({ order: order }, () => { @@ -494,6 +513,15 @@ class studentsList extends Component{ this.props.showNotification('复制成功') } + onTableChange = (pagination, filters, sorter) =>{ + this.setState({ + sortedInfo: sorter, + }, () => { + this.fetchAll(); + }); + } + + render(){ const isAdmin = this.props.isAdmin() const isSuperAdmin = this.props.isSuperAdmin() @@ -653,9 +681,9 @@ class studentsList extends Component{ {isAdmin && 已选 {checkBoxValues.length} 个}
            {isAdmin &&
          • 删除
          • } - {isAdmin &&
          • + {isAdmin &&
          • 移动到... -
              +
                { course_groups && course_groups.length > 9 ? (

                @@ -687,7 +715,7 @@ class studentsList extends Component{

              } -
            • + {/*
            • {currentOrderName} { course_groups && !!course_groups.length && @@ -698,13 +726,13 @@ class studentsList extends Component{
            } -
          • + */}
            {!this.state.isSpin && -
            +
            }
            diff --git a/public/react/src/modules/courses/members/teacherList.js b/public/react/src/modules/courses/members/teacherList.js index 70b1e3bd6..18d9a1adf 100644 --- a/public/react/src/modules/courses/members/teacherList.js +++ b/public/react/src/modules/courses/members/teacherList.js @@ -663,7 +663,7 @@ class studentsList extends Component{ + +
            +
            *问卷标题 +
            + { + // this.props.match.params.news === undefined ? "" : this.props.match.params.news === "new" ? + // ( + this.state.mysave === false ? + + : "" + // ) + // :"" + } + +
            + {/*suffix={String(addonAfter)}*/} + + + +
            +
            + + +
            问卷须知
            + + + {/**/} + { + this.state.Newedit === true || this.state.mysave === true ? +
            + + {cancellation === false ? + + : ""} + +
            + : "" + } + +
            + +
            : "" + } + + +

            + + + { + this.state.mysingles + this.state.mydoubles + this.state.mymainsint === 0 ? "" : +

            + + {this.state.mysingles === 0 ? "" : 单选题{this.state.mysingles === undefined ? "" : this.state.mysingles} 题} + + {this.state.mydoubles === 0 ? "" : + 多选题{this.state.mydoubles === undefined ? "" : this.state.mydoubles}题} + {this.state.mymainsint === 0 ? "" : + + 主观题{this.state.mymainsint === undefined ? "" : this.state.mymainsint}题 + + } + + + 合计 {this.state.q_counts === undefined ? "" : this.state.q_counts} +
            + + } + +

            + + +
            + + {/*自动生成修改好的获取到的*/} + {/**************************************************************************/} + {this.state.poll_questions === undefined ? "" : this.state.poll_questions.map((item, index) => { + console.log('打印this.state.poll_questions'); + console.log(this.state.poll_questions); + console.log(this.state.adddom); + let resultDom; + resultDom =
            +

            + {index + 1}、 + {item.question.question_type === 1 ? "单选题" : item.question.question_type === 2 ? "多选题" : "主观题"} + {item.question.is_necessary === 1 ? "(必答)" : item.question.question_type === 2 ? "(选答)" : "(选答)"} + { + item.question.question_type === 2? + {(item.question.min_choices === undefined && item.question.max_choices === undefined ? "" : item.question.min_choices === null && item.question.max_choices === null ? "" : item.question.min_choices === 0 && item.question.max_choices === 0 ? "": item.question.min_choices === "null" && item.question.max_choices === "null" ? "" : item.question.min_choices === item.question.max_choices && item.question.max_choices === item.question.min_choices ? "可选"+(item.question.max_choices)+"项" : "可选" +(item.question.min_choices===undefined||item.question.min_choices===null||item.question.min_choices===""||item.question.min_choices==="null"?2:item.question.min_choices) + "-" + (item.question.max_choices===undefined||item.question.max_choices===null||item.question.max_choices===""||item.question.max_choices==="null"?item.question.answers.length:item.question.max_choices) + "项")} + : "" + } + + { + polls_status === undefined || polls_status === 1 ? + + this.showDeleteConfirm(item.question.question_type, index, item)}> + {index === 0 ? "" : + this.handleClickBySortUp(index, item)}>} + {index === this.state.poll_questions.length - 1 ? "" : + this.handleClickBySortDown(index, item)}>} + this.addMytopic(item.question.question_type, this.state.pollid, index + 1, true, item.question.id,index)}> + this.adddomedit(item,index)}> + : this.adddomedit(item,index)}> + } + +

            +

            {item.question.question_title}

            + {/*
            {item.question.question_title}
            */} + {item.question.question_type === 1 ? +
            + + {item.question.answers === undefined ? "" : item.question.answers.map((items, i) => { + return ( +
            + + {items.answer_text} + +
            + ) + })} +
            + {/*单选题*/} + + +
            + : item.question.question_type === 2 ? +
            + + {item.question.answers === undefined ? "" : item.question.answers.map((items, i) => { + return ( +
            + + {items.answer_text} +
            + ) + })} +
            + {/*多选题*/} +
            + + : item.question.question_type === 3 ? + // 主观题 + (
            + +
            ) : (
            )} +
            + + return ( +
            + {/*这里是编辑和新增的地方*/} + { + this.state.bindingid && this.state.bindingid === item.question.id ? + (this.state.Newdisplay === false ? +
            +
            + {this.state.adddom === undefined ? "" : this.state.adddom === undefined ? "" : this.state.adddom.length === 0 ? "" : item.question.id === this.state.adddom[0].question.id && this.state.adddom.map((itemo, indexo) => { + let arrid = itemo.question.id; + let resultDomtwo; + resultDomtwo = +
            + {/*{itemo&&itemo.question&&itemo.question.question_number}、*/} + {itemo.question.question_type === 1 ? "单选题" : itemo.question.question_type === 2 ? "多选题" : "主观题"} + this.OnCheckAllChange(e, indexo)} + className="lineh-40" + style={{"marginLeft": "20px"}}>必答 + + + { + itemo.question.question_type === 3 ? + + : + + + } + {itemo.question.answers === undefined ? "" : itemo.question.answers.map((itemt, indext) => { + return ( +
            + {itemt.answer_text === undefined ? ( +
            ) : itemt.answer_text === "其他" ? ( +

            + 其它 + + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + this.Deleteentrys(arrid, indext, true)}> + + : ""} +

            ) : (

            + 选项 + + + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + // (itemo.question.question_type === 2 && itemo.question.answers.length === 3 ? + // (indext ===1? + // this.Ewoption(itemo.question.id, itemo)}> + // : + // "" + // ) + // "" + // : + itemo.question.answers.length > 2 &&indext>=1? + + { + indext > 1 ? + this.Deleteentrys(arrid, indext, false)}> + :"" + } + { + itemo.question.answers[itemo.question.answers.length - 1].answer_text === "其他" && itemo.question.answers.length - 2 === indext ? + + this.Ewoption(itemo.question.id, itemo)}> + : itemo.question.answers.length - 1 === indext ? + this.Ewoption(itemo.question.id, itemo)}> + : + } + + :itemo.question.answers.length === 2? + (indext ===1? + this.Ewoption(itemo.question.id, itemo)}> + :"") + // : "") + : "":""} +

            )} +
            + ) + })} + +
            + {itemo.question.question_type === 1 ? ( +
            + {/* this.Ewoption(itemo.question.id, itemo)}>新增选项*/} +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + "" + : ""} + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)}>保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}>保存并退出 + +
            +
            + + + ) + + + : itemo.question.question_type === 2 ? ( + //////////////////////////////////////////// 可选 +
            +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} +
            + 可选 +
            + {/*可选最小1*/} + + + ~ + {/*可选最大1*/} + + + (学生答题时,系统对其选择的选项个数进行限制,--表示不限制) + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)}>保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}>保存并退出 + +
            + +
            +
            +
            + ) + + : (
            ) + + } +
            +
            + {itemo.question.question_type === 2 ? + // ( + // this.state.polls_status === undefined || this.state.polls_status === 1 ? + //
            + // + // {/*
            this.Ewoption(itemo.question.id, itemo)}>新增选项*/} + // + // {/* {*/} + // {/* this.state.newoption === false ? this.Addanotheroption(itemo.question.id)}>新增其他选项 : ""*/} + // {/* }*/} + // + // {/*
            */} + // + // + // + // this.Deleteadddom(indexo,true)}>取消 + // this.Deleteadddomtwo(indexo, itemo,true)}>保存并继续 + // this.Deleteadddomthree(indexo, itemo,true)}>保存并退出 + // + //
            + // + // + // : + //
            + // + // this.Deleteadddom(indexo,true)}>取消 + // this.Deleteadddomtwo(indexo, itemo,true)}>保存并继续 + // this.Deleteadddomthree(indexo, itemo,true)}> 保存并退出 + // + //
            + // ) + "" + : itemo.question.question_type === 3 ? +
            + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)}>保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}>保存并退出 + +
            + : + ""} + + +
            +
            + + + return ( +
            + {resultDomtwo} +
            + ) + })} +
            +
            : "") + : + // 编辑 +
            + {resultDom} + {this.state.Newdisplay === false ? + +
            + {this.state.adddom === undefined ? "" : this.state.adddom === undefined ? "" : this.state.adddom.length === 0 ? "" : item.question.id === this.state.adddom[0].question.id && this.state.adddom.map((itemo, indexo) => { + let arrid = itemo.question.id; + let resultDomtwo; + resultDomtwo = +
            + {/*{itemo&&itemo.question&&itemo.question.question_number}、*/} + + {itemo.question.question_type === 1 ? "单选题" : itemo.question.question_type === 2 ? "多选题" : "主观题"} + this.OnCheckAllChange(e, indexo)} + className="lineh-40" + style={{"marginLeft": "20px"}}>必答 + + { + itemo.question.question_type === 3 ? + + : + + + } + {itemo.question.answers === undefined ? "" : itemo.question.answers.map((itemt, indext) => { + // console.log("chishiyong1"); + // console.log(itemo.question.answers[itemo.question.answers.length - 1]); + // var bools=true; + // if(){ + // + // } + return ( +
            + {itemt.answer_text === undefined ? ( +
            ) : itemt.answer_text === "其他" ? ( +

            + 其它 + + + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + this.Deleteentrys(arrid, indext, true)}> + + : ""} +

            ) : (

            + 选项 + + + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + // ( itemo.question.question_type === 2 && itemo.question.answers.length === 3 ? + // (indext ===1? + // this.Ewoption(itemo.question.id, itemo)}> + // :"") + itemo.question.answers.length > 2 && indext>=1 ? + + { + indext > 1 ? + this.Deleteentrys(arrid, indext, false)}> + :"" + } + { + itemo.question.answers[itemo.question.answers.length - 1].answer_text === "其他" && itemo.question.answers.length - 2 === indext ? + this.Ewoption(itemo.question.id, itemo)}> + : itemo.question.answers.length - 1 === indext ? + this.Ewoption(itemo.question.id, itemo)}> + : + + } + + :itemo.question.answers.length === 2 && indext ===1 ? + (indext ===1? + this.Ewoption(itemo.question.id, itemo)}> + :"") + // : "") + : "":""} +

            )} +
            + ) + })} + +
            + {itemo.question.question_type === 1 ? ( +
            + {/* this.Ewoption(itemo.question.id, itemo)}>新增选项*/} +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + "" + : ""} + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)}>保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}>保存并退出 + +
            +
            + + + ) + + + : itemo.question.question_type === 2 ? ( + //////////////////////////////////////////// 可选 +
            +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} +
            + 可选 +
            + {/*可选最小2*/} + + + ~ + {/*可选最大2*/} + + + (学生答题时,系统对其选择的选项个数进行限制,--表示不限制) + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)} + >保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}>保存并退出 + +
            + +
            +
            +
            + ) + + : (
            ) + + } +
            +
            + {itemo.question.question_type === 2 ? + // ( + // this.state.polls_status === undefined || this.state.polls_status === 1 ? + //
            + // + //
            this.Ewoption(itemo.question.id, itemo)}>新增选项 + // + // { + // this.state.newoption === false ? this.Addanotheroption(itemo.question.id)}>新增其他选项 : "" + // } + // + //
            + // + // + // + // this.Deleteadddom(indexo,true)}>取消 + // this.Deleteadddomtwo(indexo, itemo,true)} + // >保存并继续 + // this.Deleteadddomthree(indexo, itemo,true)}>保存并退出 + // + //
            + // + // + // : + //
            + // + // this.Deleteadddom(indexo,true)}>取消 + // this.Deleteadddomtwo(indexo, itemo,true)} + // >保存并继续 + // this.Deleteadddomthree(indexo, itemo,true)}> 保存并退出 + // + //
            + // ) + "" + + : itemo.question.question_type === 3 ? +
            + + this.Deleteadddom(indexo, true)}>取消 + this.Deleteadddomtwo(indexo, itemo, true)} + >保存并继续 + this.Deleteadddomthree(indexo, itemo, true)}> 保存并退出 + +
            + : + ""} + + +
            +
            + + + return ( +
            + {resultDomtwo} +
            + ) + })} +
            : ""} +
            + } +
            + + ) + })} + + + {/*新建单选多选2*/} +
            + { + this.state.Newdisplay === true ? +
            + {this.state.adddom === undefined ? "": this.state.adddom.map((itemo, indexo) => { + // console.log('打印this.state.adddom') + // console.log(this.state.adddom); + let arrid = itemo.question.id; + let resultDomtwo; + resultDomtwo = +
            + {/*{itemo&&itemo.question&&itemo.question.question_number}、*/} + {itemo.question.question_type === 1 ? "单选题" : itemo.question.question_type === 2 ? "多选题" : "主观题"} + this.OnCheckAllChange(e, indexo)} + className="lineh-40" + style={{"marginLeft": "20px"}}>必答 + + { + itemo.question.question_type === 3 ? + + : + + } + + + {itemo.question.answers === undefined ? "" : itemo.question.answers.map((itemt, indext) => { + console.log("ceshiyong2"); + console.log(itemo.question.answers.length - 1); + return ( +
            + {itemt.answer_text === undefined ? ( +
            ) : itemt.answer_text === "其他" ? ( +

            + 其它 + + + {polls_status === undefined || polls_status === 1 ? + + this.Deleteentrys(arrid, indext, true)}> + + : ""} +

            ) : (

            + 选项 + + + {polls_status === undefined || polls_status === 1 ? + // (itemo.question.question_type === 2&& itemo.question.answers.length === 3 ? + // (itemo.question.answers[itemo.question.answers.length-1].answer_text === "其他" &&indext ===1? + // this.Ewoption(itemo.question.id, itemo)}> + // :itemo.question.answers[itemo.question.answers.length-1].answer_text === "选项" &&indext ===1? + // this.Ewoption(itemo.question.id, itemo)}> + // :"") + // : + itemo.question.answers.length > 2 && indext>=1 ? + + { + indext>1? + this.Deleteentrys(arrid, indext, false)}> + :"" + } + + { + + itemo.question.answers[itemo.question.answers.length - 1].answer_text === "其他" && itemo.question.answers.length - 2 === indext ? + this.Ewoption(itemo.question.id, itemo)}> + : + itemo.question.answers.length - 1 === indext ? + this.Ewoption(itemo.question.id, itemo)}> + : + + + } + + : itemo.question.answers.length === 2? + (indext ===1? + this.Ewoption(itemo.question.id, itemo)}> + :"") + : "":""} +

            )} +
            + ) + })} + +
            + {itemo.question.question_type === 1 ? ( +
            + {/* this.Ewoption(itemo.question.id, itemo)}>新增选项*/} +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + "" + : ""} + {this.state.polls_status === undefined ||this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} + + this.Deleteadddom(indexo)}>取消 + this.Deleteadddomtwo(indexo, itemo)} + > 保存并继续 + this.Deleteadddomthree(indexo, itemo)}>保存并退出 + +
            +
            + + + ) + + + : itemo.question.question_type === 2 ? ( + //////////////////////////////////////////// 可选 +
            +
            + {this.state.polls_status === undefined || this.state.polls_status === 1 ? + + (this.state.newoption === false ? + this.Addanotheroption(itemo.question.id)}>添加[其它]选项 + : "") + : ""} +
            + 可选 +
            + {/*可选最小3*/} + + + ~ + {/*可选最大3*/} + + + (学生答题时,系统对其选择的选项个数进行限制,--表示不限制) + + this.Deleteadddom(indexo)}>取消 + this.Deleteadddomtwo(indexo, itemo)} + >保存并继续 + this.Deleteadddomthree(indexo, itemo)}> 保存并退出 + +
            + +
            +
            +
            + ) + + : (
            ) + + } +
            +
            + {itemo.question.question_type === 2 ? + // ( + // polls_status === undefined || polls_status === 1 ? + //
            + // + //
            this.Ewoption(itemo.question.id, itemo)}>新增选项 + // + // { + // newoption === false ? this.Addanotheroption(itemo.question.id)}>新增其他选项 : "" + // } + // + //
            + // + // + // + // this.Deleteadddom(indexo)}>取消 + // this.Deleteadddomtwo(indexo, itemo)} + // >保存并继续 + // this.Deleteadddomthree(indexo, itemo)}> 保存并退出 + // + //
            + // + // + // : + //
            + // + // this.Deleteadddom(indexo)}>取消 + // this.Deleteadddomtwo(indexo, itemo)} + // > 保存并继续 + // this.Deleteadddomthree(indexo, itemo)}>保存并退出 + // + //
            + // ) + "" + : itemo.question.question_type === 3 ? +
            + + this.Deleteadddom(indexo)}>取消 + this.Deleteadddomtwo(indexo, itemo)} + >保存并继续 + this.Deleteadddomthree(indexo, itemo)}>保存并退出 + +
            + : + ""} + + +
            +
            + + + return ( +
            + {resultDomtwo} +
            + ) + })} +
            + : + "" + } + {polls_status === undefined || polls_status === 1 ? +
            +
            + this.addmysingles()}>单选题 + this.addmydoubles()}>多选题 + this.addmymainsint()}>主观题 +
            +
            + :
            } +
            +
            +
            +
          • + {/* this.toWorkDetail()}>*/} + this.submitQuestionnaire()}>完成 +
          • + + {/**/} + +
            + + ) + } + +} + +// RouteHOC() +export default PollNewQuestbank +{/*
            */ +} +{/* {*/ +} +{/* this.props.match.params.news === "new" ?*/ +} +{/* this.state.Newedit === false ?*/ +} +{/*
            */ +} +{/*
            */ +} + +{/*
            */ +} +{/* this.addmysingles()}>单选题*/ +} +{/* this.addmydoubles()}>多选题*/ +} +{/* this.addmymainsint()}>主观题*/ +} +{/*
            */ +} +{/*
            */ +} +{/* : ""*/ +} +{/* :*/ +} +{/*
            */ +} +{/*
            */ +} +{/*
            */ +} +{/* this.addmysingles()}>单选题*/ +} +{/* this.addmydoubles()}>多选题*/ +} +{/* this.addmymainsint()}>主观题*/ +} +{/*
            */ +} +{/*
            */ +} +{/* }*/ +} +{/*
            */ +} +{/*{*/ +} +{/* this.props.match.params.news === "new" ?*/ +} +{/* (this.state.Newedit === false ?*/ +} +{/* */ +} +{/*
          • */ +} +{/* this.props.history.goBack()}>取消*/ +} +{/* this.submitQuestionnaire(this.props.match.params.news)}>提交*/ +} +{/*
          • */ +} + + +{/* */ +} + +{/* : "")*/ +} +{/* :*/ +} +{/* */ +} +{/*}*/ +} \ No newline at end of file diff --git a/public/react/src/modules/courses/poll/pollStyle.css b/public/react/src/modules/courses/poll/pollStyle.css index a486101cd..19f1b35cd 100644 --- a/public/react/src/modules/courses/poll/pollStyle.css +++ b/public/react/src/modules/courses/poll/pollStyle.css @@ -17,7 +17,22 @@ min-height: 40px; min-line-height: 40px; } - +.ml61{ + margin-left: 61px; +} +.w64{ + width: 64px; +} +.w55{ + width: 55px!important; +} +.max1010{ + width: 1010px !important; + max-width: 1010px !important; +} +.yw18{ + min-width: 18px; +} /* 选答 */ .chooseAnswer{ display: inline-block; @@ -185,7 +200,7 @@ width: 100%; } .answerList li:hover{ - background: #F8F8F8; + background: #F0F8FF; } textarea:read-only{ background: #f3f3f3; diff --git a/public/react/src/modules/courses/questionbank/Generaljobanswer.js b/public/react/src/modules/courses/questionbank/Generaljobanswer.js index 3bfc6cd36..8cc66b3f8 100644 --- a/public/react/src/modules/courses/questionbank/Generaljobanswer.js +++ b/public/react/src/modules/courses/questionbank/Generaljobanswer.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -12,6 +12,8 @@ import { } from "antd"; import GroupPackage from '../groupjobbank/GroupPackage' import './questionbank.css'; +import AttachmentsList from '../../../common/components/attachment/AttachmentList'; +import NoneData from '../../courses/coursesPublic/NoneData' class Generaljobanswer extends Component { @@ -28,7 +30,7 @@ class Generaljobanswer extends Component { console.log("componentDidMount"); // let query = this.props.location.pathname; // const type = query.split('/'); - // this.setState({ + // this.setState({n // shixuntypes:type[3] // }) // this.props.triggerRef(this); @@ -55,18 +57,77 @@ class Generaljobanswer extends Component { render() { - + let{datas}=this.props; + console.log("Generaljobanswer"); + console.log(datas.reference_attachments); + console.log(datas.reference_answer); return ( -
            +
            - -
            - - + {/*{*/} + {/* datas&&(datas.reference_answer===null?*/} + {/* */} + {/* :datas.reference_answer==="null"?*/} + {/* */} + {/* :*/} + {/* datas.reference_answer===""?*/} + {/* */} + {/* :*/} + {/* */} + + {/* //
            */} + {/* )*/} + {/*}*/} + {/*/!*
            *!/*/} + {/*
            */} + {/*{datas.reference_attachments === undefined ? "" :*/} + {/* }*/} + {/*
            */} + + { + datas.reference_answer===null? + "" + :datas.reference_answer==="null"? + "" : + datas.reference_answer===""? + "" + : + + + } + + {datas.reference_attachments === undefined ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments === "" ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments === null ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : + datas.reference_attachments.length === 0 ? + (datas.reference_answer===undefined || datas.reference_answer===null|| datas.reference_answer===""? + + : + "" + ) + : +
            + +
            + }
            diff --git a/public/react/src/modules/courses/questionbank/Generaljobbankdetails.js b/public/react/src/modules/courses/questionbank/Generaljobbankdetails.js index 29453a7b5..7aef5f743 100644 --- a/public/react/src/modules/courses/questionbank/Generaljobbankdetails.js +++ b/public/react/src/modules/courses/questionbank/Generaljobbankdetails.js @@ -1,20 +1,26 @@ import React, {Component} from "react"; -import {Link, NavLink} from 'react-router-dom'; -import {WordsBtn, ActionBtn} from 'educoder'; +import {BrowserRouter as Router,Route,Switch,Link, NavLin} from 'react-router-dom'; +import {WordsBtn, ActionBtn,getImageUrl} from 'educoder'; import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Button,Form } from "antd"; import axios from 'axios'; -import { - notification -} from "antd"; -import CoursesListType from '../coursesPublic/CoursesListType'; -import Generaljobdetails from './Generaljobdetails'; -import Generaljobanswer from './Generaljobanswer'; +import BanksMenu from '../../user/usersInfo/banks/banksMenu' +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; import '../css/members.css'; import "../common/formCommon.css"; import '../css/Courses.css'; import '../css/busyWork.css'; import '../poll/pollStyle.css'; - +// 问卷内容 +const Generaljobdetails = Loadable({ + loader: () => import('./Generaljobdetails'), + loading: Loading, +}) +// 试卷详情 +const Generaljobanswer = Loadable({ + loader: () => import('./Generaljobanswer'), + loading: Loading, +}); class Generaljobbankdetails extends Component { //普通作业内容详情 constructor(props) { @@ -25,50 +31,24 @@ class Generaljobbankdetails extends Component { workid:1, isSpin:false, datas:[], + visible:false, + banksMenu:undefined } - - } - - //切换tab - ChangeTab = (e) => { - // console.log(e); - this.setState({ - tab: e - }) - try { - var currenturl = window.location.href; - var newUrl = (currenturl.split("?"))[0]; - window.history.pushState('','',newUrl+'?tab='+e); - }catch (e) { - console.log(e); - console.log("44"); - } - } - componentDidMount() { - // console.log("父组件加载框"); - const query = this.props.location.search; - const type = query.split('?tab='); - // let sum = [] - // sum.push(type[1]) - // console.log("componentDidMountcomponentDidMount"); - // console.log(type); - this.setState({ - tab: type[1], - }); + this.getonedata(); + } - console.log("Generaljobbankdetails"); - console.log(this.props); + getonedata=()=>{ if( this.props.match.params.workid){ this.setState({ workid: this.props.match.params.workid, }) } this.getdata(this.props.match.params.workid); - } + }; //获取数据的地方 getdata=(workid)=>{ var workids= workid; @@ -86,8 +66,37 @@ class Generaljobbankdetails extends Component { if(response){ if(response.data){ this.setState({ - datas:response.data.informs, + datas:response.data, }) + try { + const crumbData={ + title:response && response.data && response.data.name, + is_public:response && response.data && response.data.is_public, + crumbArray:[ + {content:'详情'} + ] + }; + const menuData={ + tab:'0',//tab选中的index + menuArray:[//tab以及tab路由 + {to:`/banks/normal/${workids}/${this.props.match.params.type}?tab=0`,content:'内容详情'}, + {to:`/banks/normal/${workids}/${this.props.match.params.type}/answer?tab=1`,content:'参考答案'} + ], + category:'normal',//毕设选题 + tos:`/banks/normal/${workids}/edit/${this.props.match.params.type}?tab=0`, + id:workids, + is_public:response && response.data && response.data.is_public, + type:this.props.match.params.type, + authorize:response && response.data && response.data.authorize, + + } + this.setState({ + banksMenu:menuData + }) + this.props.initPublic(crumbData,response.data); + }catch (e) { + + } }else { this.setState({ datas:[], @@ -111,63 +120,51 @@ class Generaljobbankdetails extends Component { isSpin:false, }) }); - } - - - bindRef = ref => { this.child = ref } -///////////////教师截止 + }; + // initPublic = (crumbData,menuData) =>{ + // this.setState({ + // banksMenu:menuData + // }) + // this.props.initPublic(crumbData); + // } render() { - let {tab} = this.state; - - const isAdmin = this.props.isAdmin(); - // console.log(119) + let {tab,datas,visible} = this.state; + let{ + banksMenu + }=this.state return ( -
            - - -
            - -
            -

            - 题库 - > - 详情 -

            -
            -
            -

            - MySQL数据库编程开发实训(基础篇) -

            - + +
            + { + banksMenu && + + } + + { + return () + } + }> + { + return () + } + }> + +
            - - - - {parseInt(tab) === 0 ? :""} - {parseInt(tab) === 1 ? :""} - -
            -
            + ) } } export default Generaljobbankdetails; - diff --git a/public/react/src/modules/courses/questionbank/Generaljobdetails.js b/public/react/src/modules/courses/questionbank/Generaljobdetails.js index 9de444123..178328347 100644 --- a/public/react/src/modules/courses/questionbank/Generaljobdetails.js +++ b/public/react/src/modules/courses/questionbank/Generaljobdetails.js @@ -1,5 +1,6 @@ + import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,markdownToHTML, MarkdownToHtml ,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -12,15 +13,15 @@ import { } from "antd"; import GroupPackage from '../groupjobbank/GroupPackage' import './questionbank.css'; - - +import AttachmentsList from "../../../common/components/attachment/AttachmentList"; +import NoneData from '../../courses/coursesPublic/NoneData' +//内容详情 class Generaljobdetails extends Component { constructor(props) { super(props); this.state = { - } } @@ -56,21 +57,56 @@ class Generaljobdetails extends Component { render() { - + let{datas}=this.props; return ( -
            +
            - -
            - - + { + datas.description===null? + "" + :datas.description==="null"? + "" + :datas&&datas.description===""? + "" + : + + //
            + } + {datas.attachments === undefined ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments=== "" ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments=== null ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : + datas.attachments.length === 0 ? + (datas.description === undefined || datas.description === null || datas.description === "" ? + + : + "" + ) + : +
            + +
            + }
            -
            diff --git a/public/react/src/modules/courses/questionbank/questionbank.css b/public/react/src/modules/courses/questionbank/questionbank.css index 43dcfa9c6..ce7aa7ddf 100644 --- a/public/react/src/modules/courses/questionbank/questionbank.css +++ b/public/react/src/modules/courses/questionbank/questionbank.css @@ -2,10 +2,10 @@ padding-top: 30px !important; padding-right: 30px !important; padding-left: 30px !important; + min-height: 500px !important; } .yslquesHeigth{ - min-height: 500px !important; - + width: 100% !important; } .yslquesmarkdowntext{ font-size: 16px; @@ -23,4 +23,11 @@ .ysltextcolor99999{ color: #999999; font-size: 16px; +} +.mt16px{ + margin-top: 16px; + padding-bottom: 30px; +} +.pd30{ + padding-bottom: 30px; } \ No newline at end of file diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js index bba76386a..7aac55b20 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -67,7 +67,7 @@ class Listofworksstudentone extends Component { pages: 1, limit: 20, loadingstate: true, - order: "update_time", + order: "", search: null, day: 0, hour: 0, @@ -93,27 +93,32 @@ class Listofworksstudentone extends Component { key: 'number', align: "center", className:'font-14', + width:'100px', render: (text, record) => ( - + {record.number === undefined ? -- : record.number === "" ? -- : record.number === "--" ? -- : {record.number} } @@ -124,37 +129,42 @@ class Listofworksstudentone extends Component { dataIndex: 'name', key: 'name', align: "center", - className:'font-14 maxnamewidth100', + className:'font-14 maxnamewidth110', width:'100px', render: (text, record) => ( - + {record.name === undefined ? -- : record.name === "" ? -- : record.name === null ? -- : record.name === "--" ? -- : - {record.name} } @@ -166,35 +176,41 @@ class Listofworksstudentone extends Component { dataIndex: 'stduynumber', key: 'stduynumber', align: "center", - className:'font-14 maxnamewidth110', - width:'110px', + className:'font-14 maxnamewidth145', + width:'145px', render: (text, record) => ( - + {record.stduynumber === undefined ? -- : record.stduynumber === null ? -- : record.stduynumber === "" ? -- : { record.stduynumber } @@ -210,13 +226,38 @@ class Listofworksstudentone extends Component { key: 'classroom', dataIndex: 'classroom', align: "center", - className:'font-14', + className:'font-14 maxnamewidth145', + width:'145px', render: (text, record) => ( - - {record.classroom === undefined ? "--" : record.classroom === "" ? "--" : record.classroom === null ? "--" : record.classroom} + + {record.classroom === undefined ? + -- : record.classroom === "" ? + -- : record.classroom === null ? + -- + : + {record.classroom} + } ), }, @@ -226,14 +267,17 @@ class Listofworksstudentone extends Component { key: 'submitstate', align: "center", className:'font-14', + width:'98px', render: (text, record) => ( - + {record.submitstate === undefined ? "--" : record.submitstate === "" ? "--" : record.submitstate === null ? "--" : record.submitstate} @@ -245,41 +289,409 @@ class Listofworksstudentone extends Component { key: 'cost_time', align: 'center', className:'font-14', + width:'145px', render: (text, record) => ( {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time } + }> + {record.cost_time === null? "--":record.cost_time === undefined?"--":record.cost_time === "--"?"--": + + 学员在EduCoder做实训花费的时间 +
            }> + {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time} + + + } + + ) + + }, + // { + // title: '更新时间', + // dataIndex: 'updatetime', + // key: 'updatetime', + // align: "center", + // className:'font-14', + // render: (text, record) => ( + // + // {record.updatetime === undefined ? "--" : record.updatetime === "" ? "--" : record.updatetime} + // + // ), + // }, + { + title: '完成情况', + dataIndex: 'completion', + key: 'completion', + align: "center", + className:'font-14', + width:'99px', + render: (text, record) => ( + + {record.completion+"/"+this.state.challenges_count} + + ), + }, + { + title: '关卡得分', + dataIndex: 'levelscore', + key: 'levelscore', + align: 'center', + className:'font-14', + width:'99px', + render: (text, record) => ( + + = 90 ? {color: '#DD1717', textAlign: "center", width:'99px',} : { + color: '#747A7F', + textAlign: "center", + width:'99px', + }}>{record.levelscore} ) + }, + { + title: '效率分', + dataIndex: 'efficiencyscore', + key: 'efficiencyscore', + align: 'center', + className:'font-14', + width:'80px', + render: (text, record) => ( + + { + record.efficiencyscore&& record.efficiencyscore=== "--"?( + + -- + + ) + : + = 90 ? { + color: '#DD1717', + textAlign: "center", + width:'80px', + } : {color: '#747A7F', textAlign: "center", width:'80px',}}>{record.efficiencyscore} + } + + + ) + }, + { + title: '最终成绩', + dataIndex: 'levelscore', + key: 'levelscore', + align: "center", + className:'font-14', + width:'99px', + render: (text, record) => ( + + { + record.levelscore && record.levelscore === "--"? + {record.levelscore} + : + =90 ? { + color: '#DD1717', + textAlign: "center", + width:'99px', + } : parseInt(record.levelscore) <= 60?{ + color: '#FF6800', + textAlign: "center", + width:'99px', + }: {color: '#747A7F', textAlign: "center",width:'99px',}}>{record.levelscore} + } + + ), }, { - title: '更新时间', - dataIndex: 'updatetime', - key: 'updatetime', + title: '操作', + dataIndex: 'operating', + key: 'operating', align: "center", className:'font-14', render: (text, record) => ( - {record.updatetime === undefined ? "--" : record.updatetime === "" ? "--" : record.updatetime} + { + record.submitstate === "未提交" ?-- + : + this.Viewstudenttraininginformation(record)}>{record.operating} + } + + + ), + }, + ], + orders: "", + columnsstu2: [ + { + title: '序号', + dataIndex: 'number', + key: 'number', + align: "center", + className:'font-14', + width:'100px', + render: (text, record) => ( + + + + ), + }, + { + title: '姓名', + dataIndex: 'name', + key: 'name', + align: "center", + className:'font-14 maxnamewidth110', + width:'100px', + render: (text, record) => ( + + {record.name === undefined ? + -- + : + record.name === "" ? + -- + : + record.name === null ? + -- + : + record.name === "--" ? + -- + : + {record.name} + } + + + ), + }, + { + title: '学号', + dataIndex: 'stduynumber', + key: 'stduynumber', + align: "center", + className:'font-14 maxnamewidth145', + width:'145px', + render: (text, record) => ( + + {record.stduynumber === undefined ? + -- + + : record.stduynumber === null ? + -- + + : record.stduynumber === "" ? + -- + + : + { + record.stduynumber + } + + + } + + + ), + }, + { + title: '分班', + key: 'classroom', + dataIndex: 'classroom', + align: "center", + className:'font-14 maxnamewidth145', + width:'145px', + render: (text, record) => ( + + {record.classroom === undefined ? + -- : record.classroom === "" ? + -- : record.classroom === null ? + -- + : + {record.classroom} + } + + ), + }, + { + title: '提交状态', + dataIndex: 'submitstate', + key: 'submitstate', + align: "center", + className:'font-14', + width:'98px', + render: (text, record) => ( + + {record.submitstate === undefined ? "--" : record.submitstate === "" ? "--" : record.submitstate === null ? "--" : record.submitstate} + ), }, + { + title: '实战耗时', + dataIndex: 'cost_time', + key: 'cost_time', + align: 'center', + className:'font-14', + width:'145px', + render: (text, record) => ( + + {record.cost_time === null? "--":record.cost_time === undefined?"--":record.cost_time === "--"?"--": + {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time} + + } + + ) + + }, + // { + // title: '更新时间', + // dataIndex: 'updatetime', + // key: 'updatetime', + // align: "center", + // className:'font-14', + // render: (text, record) => ( + // + // {record.updatetime === undefined ? "--" : record.updatetime === "" ? "--" : record.updatetime} + // + // ), + // }, { title: '完成情况', dataIndex: 'completion', key: 'completion', align: "center", className:'font-14', + width:'99px', render: (text, record) => ( - - {record.completion+"/"+this.state.challenges_count} + + {record.completion+"/"+this.state.challenges_count} ), }, @@ -289,17 +701,23 @@ class Listofworksstudentone extends Component { key: 'levelscore', align: 'center', className:'font-14', + width:'99px', render: (text, record) => ( - + = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', - "text-align": "center" + color: '#FF6800', + textAlign: "center", + width:'99px', + } : parseInt(record.levelscore) >= 90 ? {color: '#DD1717', textAlign: "center", width:'99px',} : { + color: '#747A7F', + textAlign: "center", + width:'99px', }}>{record.levelscore} ) @@ -310,25 +728,31 @@ class Listofworksstudentone extends Component { key: 'efficiencyscore', align: 'center', className:'font-14', + width:'80px', render: (text, record) => ( - + { record.efficiencyscore&& record.efficiencyscore=== "--"?( - + -- ) : = 90 ? { - "color": '#DD1717', - "text-align": "center" - } : {"color": '#747A7F', "text-align": "center"}}>{record.efficiencyscore} + color: '#DD1717', + textAlign: "center", + width:'80px', + } : {color: '#747A7F', textAlign: "center", width:'80px',}}>{record.efficiencyscore} } @@ -340,19 +764,22 @@ class Listofworksstudentone extends Component { key: 'levelscore', align: "center", className:'font-14', + width:'99px', render: (text, record) => ( - + { record.levelscore && record.levelscore === "--"? - {record.levelscore} + {record.levelscore} : =90 ? { - "color": '#DD1717', - "text-align": "center" + color: '#DD1717', + textAlign: "center", + width:'99px', } : parseInt(record.levelscore) <= 60?{ - "color": '#FF6800', - "text-align": "center", - }: {"color": '#747A7F', "text-align": "center"}}>{record.levelscore} + color: '#FF6800', + textAlign: "center", + width:'99px', + }: {color: '#747A7F', textAlign: "center",width:'99px',}}>{record.levelscore} } @@ -370,16 +797,14 @@ class Listofworksstudentone extends Component { record.submitstate === "未提交" ?-- : this.Viewstudenttraininginformation(record)}>{record.operating} + className="color-blue" + onClick={() => this.Viewstudenttraininginformation(record)}>{record.operating} } ), }, ], - - orders: "update_time", b_order:"desc", allow_late:false, checkedValuesine: undefined, @@ -395,8 +820,8 @@ class Listofworksstudentone extends Component { course_group: null, publish_immediately: undefined, end_immediately: undefined, - mystyle: {"display": "block", "color": '#07111B', "text-align": "center"}, - mystyles: {"display": "none", "color": '#07111B', "text-align": "center"}, + mystyle: {"display": "block", color: '#07111B', textAlign: "center"}, + mystyles: {"display": "none", color: '#07111B', textAlign: "center"}, mystyle1: {"display": "block"}, mystyles1: {"display": "none"}, unlimited: 0, @@ -413,7 +838,7 @@ class Listofworksstudentone extends Component { align: 'center', className:'font-14', render: (text, record) => ( - {record.number} + {record.number} ) }, @@ -425,7 +850,7 @@ class Listofworksstudentone extends Component { className:'font-14 maxnamewidth100', width:'100px', render: (text, record) => ( - {record.name} + {record.name} ) }, { @@ -434,25 +859,24 @@ class Listofworksstudentone extends Component { key: 'stduynumber', align: "center", className:'font-14 maxnamewidth110', - width:'110px', render: (text, record) => ( {record.stduynumber === undefined ? -- : record.stduynumber === null ? -- : record.stduynumber === "" ? -- : @@ -460,8 +884,8 @@ class Listofworksstudentone extends Component { title={record.stduynumber} className="maxnamewidth110" style={{ - "color": '#9A9A9A', - "text-align": "center" + color: '#9A9A9A', + textAlign: "center" }}>{ record.stduynumber } @@ -480,7 +904,7 @@ class Listofworksstudentone extends Component { className:'font-14', render: (text, record) => ( - {record.classroom === undefined ? -- : record.classroom === "" ? --: record.classroom === null ? -- : {record.classroom}} + {record.classroom === undefined ? -- : record.classroom === "" ? --: record.classroom === null ? -- : {record.classroom}} ) }, @@ -492,11 +916,11 @@ class Listofworksstudentone extends Component { className:'font-14', render: (text, record) => ( {record.submitstate} ) @@ -511,24 +935,44 @@ class Listofworksstudentone extends Component { render: (text, record) => ( {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time } - + }> + {record.cost_time === null? "--":record.cost_time === undefined?"--":record.cost_time === "--"?"--": + + {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time} + + } + + // {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time } + // ) }, - { - title: '更新时间', - dataIndex: 'updatetime', - key: 'updatetime', - align: 'center', - className:'font-14', - render: (text, record) => ( - {record.updatetime} - ), - }, + // { + // title: '更新时间', + // dataIndex: 'updatetime', + // key: 'updatetime', + // align: 'center', + // className:'font-14', + // render: (text, record) => ( + // {record.updatetime} + // ), + // }, { title: '完成情况', dataIndex: 'completion', @@ -541,7 +985,7 @@ class Listofworksstudentone extends Component {
            已通过{record.completion}关,共{this.state.challenges_count}关
            }> - {record.completion+"/"+this.state.challenges_count} + {record.completion+"/"+this.state.challenges_count} @@ -556,13 +1000,13 @@ class Listofworksstudentone extends Component { render: (text, record) => ( = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', + } : parseInt(record.levelscore) >= 90 ? {color: '#DD1717', "text-align": "center"} : { + color: '#747A7F', "text-align": "center" }}>{record.levelscore} @@ -602,15 +1046,15 @@ class Listofworksstudentone extends Component { ) : = 90 ? { - "color": '#DD1717', + color: '#DD1717', "text-align": "center" - } : {"color": '#747A7F', "text-align": "center"}}>{record.efficiencyscore} + } : {color: '#747A7F', "text-align": "center"}}>{record.efficiencyscore} } @@ -634,18 +1078,18 @@ class Listofworksstudentone extends Component { record.finalscore&&record.finalscore==="--"? {record.finalscore} : = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', + } : parseInt(record.finalscore) >= 90 ? {color: '#DD1717', "text-align": "center"} : { + color: '#747A7F', "text-align": "center" }}>{record.finalscore} } @@ -662,18 +1106,18 @@ class Listofworksstudentone extends Component { record.finalscore&&record.finalscore==="--"? {record.finalscore} : = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', + } : parseInt(record.finalscore) >= 90 ? {color: '#DD1717', "text-align": "center"} : { + color: '#747A7F', "text-align": "center" }}>{record.finalscore} } @@ -707,7 +1151,7 @@ class Listofworksstudentone extends Component { align: 'center', className:'font-14', render: (text, record) => ( - {record.number} + {record.number} ) }, @@ -719,7 +1163,7 @@ class Listofworksstudentone extends Component { className:'font-14 maxnamewidth100', width:'100px', render: (text, record) => ( - {record.name} + {record.name} ) }, { @@ -728,24 +1172,23 @@ class Listofworksstudentone extends Component { key: 'stduynumber', align: "center", className:'font-14 maxnamewidth110', - width:'110px', render: (text, record) => ( {record.stduynumber === undefined ? -- : record.stduynumber === null ? -- : record.stduynumber === "" ? -- @@ -754,8 +1197,8 @@ class Listofworksstudentone extends Component { title={record.stduynumber} className="maxnamewidth110" style={{ - "color": '#9A9A9A', - "text-align": "center" + color: '#9A9A9A', + textAlign: "center" }}>{ record.stduynumber } @@ -774,7 +1217,7 @@ class Listofworksstudentone extends Component { className:'font-14', render: (text, record) => ( - {record.classroom === undefined ? -- : record.classroom === "" ? --: record.classroom === null ? -- : {record.classroom}} + {record.classroom === undefined ? -- : record.classroom === "" ? --: record.classroom === null ? -- : {record.classroom}} ) }, @@ -786,26 +1229,26 @@ class Listofworksstudentone extends Component { className:'font-14', render: (text, record) => ( {record.submitstate} ) }, - { - title: '更新时间', - dataIndex: 'updatetime', - key: 'updatetime', - align: 'center', - className:'font-14', - render: (text, record) => ( - {record.updatetime} - ), - }, + // { + // title: '更新时间', + // dataIndex: 'updatetime', + // key: 'updatetime', + // align: 'center', + // className:'font-14', + // render: (text, record) => ( + // {record.updatetime} + // ), + // }, { title: '实战耗时', dataIndex: 'cost_time', @@ -815,13 +1258,26 @@ class Listofworksstudentone extends Component { render: (text, record) => ( {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time } - + }> + {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time === "--" ?"--": + + 学员在EduCoder做实训花费的时间 +
            }> + {record.cost_time === null ? "--":record.cost_time === undefined ?"--":record.cost_time} + + + } + ) - }, { title: '完成情况', @@ -835,7 +1291,7 @@ class Listofworksstudentone extends Component {
            已通过{record.completion}关,共{this.state.challenges_count}关
            }> - {record.completion+"/"+this.state.challenges_count} + {record.completion+"/"+this.state.challenges_count} @@ -850,14 +1306,14 @@ class Listofworksstudentone extends Component { render: (text, record) => ( = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', - "text-align": "center" + color: '#FF6800', + textAlign: "center" + } : parseInt(record.levelscore) >= 90 ? {color: '#DD1717', textAlign: "center"} : { + color: '#747A7F', + textAlign: "center" }}>{record.levelscore} ) @@ -896,15 +1352,15 @@ class Listofworksstudentone extends Component { ) : = 90 ? { - "color": '#DD1717', - "text-align": "center" - } : {"color": '#747A7F', "text-align": "center"}}>{record.efficiencyscore} + color: '#DD1717', + textAlign: "center" + } : {color: '#747A7F',textAlign: "center"}}>{record.efficiencyscore} } @@ -928,19 +1384,19 @@ class Listofworksstudentone extends Component { record.finalscore&&record.finalscore==="--"? {record.finalscore} : = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', - "text-align": "center" + color: '#FF6800', + textAlign: "center" + } : parseInt(record.finalscore) >= 90 ? {color: '#DD1717', textAlign: "center"} : { + color: '#747A7F', + textAlign: "center" }}>{record.finalscore} } @@ -956,19 +1412,19 @@ class Listofworksstudentone extends Component { record.finalscore&&record.finalscore==="--"? {record.finalscore} : = 90 ? {"color": '#DD1717', "text-align": "center"} : { - "color": '#747A7F', - "text-align": "center" + color: '#FF6800', + textAlign: "center" + } : parseInt(record.finalscore) >= 90 ? {color: '#DD1717', textAlign: "center"} : { + color: '#747A7F', + textAlign: "center" }}>{record.finalscore} } @@ -997,10 +1453,6 @@ class Listofworksstudentone extends Component { datajs:[], } - // console.log("902"); - // console.log("902"); - // console.log(this.props); - } componentDidCatch(error, info){ console.log("-----------------------------905错误信息"); @@ -1037,6 +1489,11 @@ class Listofworksstudentone extends Component { // this.Gettitleinformation(homeworkid); this.Getalistofworks(homeworkid); } + Isupdatass = () => { + var homeworkid = this.props.match.params.homeworkid; + // this.Gettitleinformation(homeworkid); + this.Getalistofworks(homeworkid); + } /////////老师操作 // tearchar=()=>{ // var homeworkid = this.props.match.params.homeworkid; @@ -1077,13 +1534,13 @@ class Listofworksstudentone extends Component { // debugger let urll = `/homework_commons/${homeworkid}/works_list.json`; var datasysl = { - search: "", - order: "", + search: this.state.searchtext, + order: this.state.orders, b_order: "desc", - page: 1, - limit: 20, - work_status: "", - course_group: "", + page: this.state.page, + limit: this.state.limit, + work_status: this.state.course_groupyslstwo, + course_group: this.state.checkedValuesineinfo, } axios.post(urll, datasysl).then((result) => { console.log("980000000____________________"); @@ -1201,6 +1658,7 @@ class Listofworksstudentone extends Component { let datalists = []; var styletable = {"display": "none"} var arr =[]; + var arr2=[]; for(var i=0;i { // console.log("viewtraining") @@ -1654,9 +2203,9 @@ class Listofworksstudentone extends Component { var homeworkid = this.props.match.params.homeworkid; let urll = `/homework_commons/${homeworkid}/works_list.json?`; var order = "asc"; - if (ordervlue === "update_time") { - order = "desc"; - } + // if (ordervlue === "update_time") { + // order = "desc"; + // } var checkedValuesines = checkedValuesine; var checkedValuesineinfos = checkedValuesineinfo; var searchtexts = searchtext @@ -2063,15 +2612,15 @@ class Listofworksstudentone extends Component { } //排序 funordert = (e) => { - if (e === "update_time") { - // 时间 - // 时间排序是从小到大 - this.setState({ - orders: "update_time", - loadingstate: true, - }) - this.Startsortingt("update_time", this.state.course_groupyslstwo, this.state.checkedValuesineinfo, this.state.searchtext, this.state.page, this.state.limit); - } + // if (e === "update_time") { + // // 时间 + // // 时间排序是从小到大 + // this.setState({ + // orders: "update_time", + // loadingstate: true, + // }) + // this.Startsortingt("update_time", this.state.course_groupyslstwo, this.state.checkedValuesineinfo, this.state.searchtext, this.state.page, this.state.limit); + // } if (e === "work_score") { // 成绩 @@ -2104,7 +2653,8 @@ class Listofworksstudentone extends Component { this.setState({ userids: e.myid, }) - this.viewtrainingt(e.myid); + // this.viewtrainingt(e.myid); + window.open(`/courses/${this.state.props.match.params.coursesId}/shixun_homeworks/${e.myid}/shixun_work_report`, '_blank'); } // 关闭调分 cancelModulationModels = () => { @@ -2470,8 +3020,9 @@ class Listofworksstudentone extends Component { }) } }else { - this.props.showNotification(`正在下载中`); - window.open("/api"+url, '_blank'); + // this.props.showNotification(`正在下载中`); + // window.open("/api"+url, '_blank'); + this.props.slowDownload(url); } }).catch((error) => { console.log(error) @@ -2486,7 +3037,7 @@ class Listofworksstudentone extends Component { }) } render() { - let {columns,course_groupysls,datajs,isAdmin, course_groupyslstwo, unlimited, unlimitedtwo, course_group_info, orders, task_status, checkedValuesine, searchtext, teacherlist, visible,visibles, game_list,columnsstu, limit,experience, boolgalist,viewtrainingdata, teacherdata, page, data, jobsettingsdata, styletable, datas, order, loadingstate,computeTimetype} = this.state; + let {columns,course_groupysls,datajs,isAdmin, course_groupyslstwo, unlimited, unlimitedtwo, course_group_info, orders, task_status, checkedValuesine, searchtext, teacherlist, visible,visibles, game_list,columnsstu,columnsstu2, limit,experience, boolgalist,viewtrainingdata, teacherdata, page, data, jobsettingsdata, styletable, datas, order, loadingstate,computeTimetype} = this.state; const antIcon = ; // console.log(this.state.student_works); @@ -2501,6 +3052,21 @@ class Listofworksstudentone extends Component { // console.log(this.props.isAdmin()); let course_is_end = this.props.current_user&&this.props.current_user.course_is_end; + try { + if(this.props.isAdmin() === false){ + if(teacherdata&&teacherdata.student_works){ + if(teacherdata&&teacherdata.student_works.length>0){ + console.log("这是双层页面。。。。"); + + } + } + + } + }catch (e) { + console.log("Listofworksstudentone123"); + console.log(e); + } + return ( this.props.isAdmin() === true ? ( @@ -2600,29 +3166,31 @@ class Listofworksstudentone extends Component { color:rgba(255,104,0,1); } - .computeTime{ - width: 73px; - height: 24px; - display: inline-block; - padding: 5px; - text-align: center; - line-height: 13px; - color: #4CACFF; - border: 1px solid #4CACFF; - cursor: pointer; - } + .computeTime { + width: 122px; + height: 31px; + display: inline-block; + padding: 5px; + text-align: center; + line-height: 20px; + color: #FE6B21; + border: 1px solid #FE6B21; + cursor: pointer; + border-radius: 4px; + } - .computeTimes{ - width: 73px; - height: 24px; - display: inline-block; - padding: 5px; - text-align: center; - line-height: 13px; - color: #C5C5C5; - border: 1px solid #EDEDED; - background:#EDEDED; - cursor: pointer; + .computeTimes{ + width: 122px; + height: 31px; + display: inline-block; + padding: 5px; + text-align: center; + line-height: 20px; + color: #C5C5C5; + border: 1px solid #EDEDED; + background:#EDEDED; + cursor: pointer; + border-radius: 4px; } .shixunSpin{ color:#FF6801; @@ -2639,21 +3207,23 @@ class Listofworksstudentone extends Component { {/*作品状态GraduationTaskssettinglist*/}