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 a901bc5b5..7f2c08a0d 100644 --- a/Gemfile +++ b/Gemfile @@ -95,6 +95,7 @@ gem 'bulk_insert' gem 'searchkick' gem 'aasm' +gem 'enumerize' # oauth2 gem 'omniauth', '~> 1.9.0' diff --git a/Gemfile.lock b/Gemfile.lock index 96534ef5d..19a413f2f 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) @@ -184,7 +186,7 @@ GEM omniauth (~> 1.9) 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) @@ -372,6 +374,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 3e9601bf8..c69986a57 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -13,10 +13,15 @@ //= require bootstrap-datepicker //= require bootstrap.viewer //= require jquery.mloading +//= require jquery-confirm.min +//= 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 +45,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(); // 图片查看大图 @@ -83,4 +96,4 @@ $(document).on("turbolinks:before-cache", function () { // }); $(function () { -}); \ No newline at end of file +}); 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/batch-check-box.js b/app/assets/javascripts/admins/batch-check-box.js new file mode 100644 index 000000000..63963f0d9 --- /dev/null +++ b/app/assets/javascripts/admins/batch-check-box.js @@ -0,0 +1,12 @@ +$(document).on('turbolinks:load', function(){ + $(document).on('click', '.batch-all-check-box', function(){ + var $checkAll = $(this); + + $('.batch-check-box').prop('checked', $checkAll.is(':checked')); + }) + + $(document).on('click', '.batch-check-box', function(){ + var allChecked = $('.batch-check-box:checked').length === $('.batch-check-box').length + $('.batch-all-check-box').prop('checked', allChecked); + }) +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/common-refuse-modal.js b/app/assets/javascripts/admins/common-refuse-modal.js index 4e1af891e..886c00570 100644 --- a/app/assets/javascripts/admins/common-refuse-modal.js +++ b/app/assets/javascripts/admins/common-refuse-modal.js @@ -3,6 +3,7 @@ $(document).on('turbolinks:load', function() { 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', @@ -21,9 +22,19 @@ $(document).on('turbolinks:load', function() { 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(){ @@ -40,9 +51,10 @@ $(document).on('turbolinks:load', function() { if ($form.valid()) { var url = $form.data('url'); + var form_method = $form.data('type'); $.ajax({ - method: 'POST', + method: form_method, dataType: 'script', url: url, data: $form.serialize(), 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/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/identity_authentications/index.js b/app/assets/javascripts/admins/identity_authentications/index.js index 91ce5c7ec..2957e4728 100644 --- a/app/assets/javascripts/admins/identity_authentications/index.js +++ b/app/assets/javascripts/admins/identity_authentications/index.js @@ -10,11 +10,41 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('select[name="status"]').val('processed'); if($link.data('value') === 'processed'){ + $('.batch-action-container').hide(); $searchFrom.find('.status-filter').show(); } else { + $('.batch-action-container').show(); $searchFrom.find('.status-filter').hide(); $searchFrom.find('select[name="status"]').val('pending'); } }); + + $('.batch-agree-btn').on('click', function(){ + if($('.batch-check-box:checked').length === 0){ + $.notify({ message: '请先选择数据' }, { type: 'info' }); + return; + } + + customConfirm({ + content: '确认审核通过?', + ok: function(){ + var ids = $('.batch-check-box:checked').map(function(_, e){ return $(e).val() }).get(); + + $.ajax({ + url: '/admins/identity_authentications/batch_agree', + method: 'POST', + dataType: 'json', + data: { ids: ids }, + success: function(data){ + $.notify({ message: '操作成功' }); + window.location.reload(); + }, + error: function(res){ + $.notify({ message: res.responseJSON.message }, { type: 'danger' }); + } + }) + } + }) + }) } }) \ 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/message-modal.js b/app/assets/javascripts/admins/message-modal.js index 227d75776..2c9ce27a7 100644 --- a/app/assets/javascripts/admins/message-modal.js +++ b/app/assets/javascripts/admins/message-modal.js @@ -1,14 +1,22 @@ $(document).on('turbolinks:load', function() { var $modal = $('.modal.admin-message-modal'); + var $submitBtn = $modal.find('.submit-btn'); if ($modal.length > 0) { $modal.on('hide.bs.modal', function(){ $modal.find('.modal-body').html(''); + $submitBtn.unbind(); }); } }); -function showMessageModal(html) { +function showMessageModal(html, callback) { var $modal = $('.modal.admin-message-modal'); + var $submitBtn = $modal.find('.submit-btn'); + $submitBtn.unbind(); + if(callback !== undefined && typeof callback === 'function'){ + $submitBtn.on('click', callback); + } + $modal.find('.modal-body').html(html); $modal.modal('show'); } \ No newline at end of file diff --git a/app/assets/javascripts/admins/modals/admin-import-customer-member-modal.js b/app/assets/javascripts/admins/modals/admin-import-customer-member-modal.js new file mode 100644 index 000000000..01038c7de --- /dev/null +++ b/app/assets/javascripts/admins/modals/admin-import-customer-member-modal.js @@ -0,0 +1,78 @@ +$(document).on('turbolinks:load', function() { + var $modal = $('.modal.admin-import-course-member-modal'); + if ($modal.length > 0) { + var $form = $modal.find('form.admin-import-course-member-form'); + + var resetFileInputFunc = function(file){ + file.after(file.clone().val("")); + file.remove(); + } + + $modal.on('show.bs.modal', function(){ + $modal.find('.file-names').html('选择文件'); + $modal.find('.upload-file-input').trigger('click'); + }); + $modal.on('hide.bs.modal', function(){ + resetFileInputFunc($modal.find('.upload-file-input')); + }); + $modal.on('change', '.upload-file-input', function(e){ + var file = $(this)[0].files[0]; + $modal.find('.file-names').html(file ? file.name : '请选择文件'); + }) + + var importFormValid = function(){ + if($form.find('input[name="file"]').val() == undefined || $form.find('input[name="file"]').val().length == 0){ + $form.find('.error').html('请选择文件'); + return false; + } + + return true; + }; + + var buildResultMessage = function(data){ + var messageHtml = "
导入结果:成功" + data.success + "条,失败"+ data.fail.length + "条
"; + + if(data.fail.length > 0){ + messageHtml += ''; + + data.fail.forEach(function(item){ + messageHtml += ''; + }); + + messageHtml += '
数据失败原因
' + item.data + '' + item.message + '
' + } + + return messageHtml; + } + + $modal.on('click', '.submit-btn', function(){ + $form.find('.error').html(''); + + if (importFormValid()) { + $('body').mLoading({ text: '正在导入...' }); + + $.ajax({ + method: 'POST', + dataType: 'json', + url: '/admins/import_course_members', + data: new FormData($form[0]), + processData: false, + contentType: false, + success: function(data){ + $('body').mLoading('destroy'); + $modal.modal('hide'); + + showMessageModal(buildResultMessage(data), function(){ + window.location.reload(); + }); + }, + error: function(res){ + $('body').mLoading('destroy'); + var data = res.responseJSON; + $form.find('.error').html(data.message); + } + }); + } + }); + } +}); \ 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/professional_authentications/index.js b/app/assets/javascripts/admins/professional_authentications/index.js index 82a1da5af..8edfeae70 100644 --- a/app/assets/javascripts/admins/professional_authentications/index.js +++ b/app/assets/javascripts/admins/professional_authentications/index.js @@ -10,11 +10,41 @@ $(document).on('turbolinks:load', function() { $searchFrom.find('select[name="status"]').val('processed'); if($link.data('value') === 'processed'){ + $('.batch-action-container').hide(); $searchFrom.find('.status-filter').show(); } else { + $('.batch-action-container').show(); $searchFrom.find('.status-filter').hide(); $searchFrom.find('select[name="status"]').val('pending'); } }); + + $('.batch-agree-btn').on('click', function(){ + if($('.batch-check-box:checked').length === 0){ + $.notify({ message: '请先选择数据' }, { type: 'info' }); + return; + } + + customConfirm({ + content: '确认审核通过?', + ok: function(){ + var ids = $('.batch-check-box:checked').map(function(_, e){ return $(e).val() }).get(); + + $.ajax({ + url: '/admins/professional_authentications/batch_agree', + method: 'POST', + dataType: 'json', + data: { ids: ids }, + success: function(data){ + $.notify({ message: '操作成功' }); + window.location.reload(); + }, + error: function(res){ + $.notify({ message: res.responseJSON.message }, { type: 'danger' }); + } + }) + } + }) + }) } }) \ No newline at end of file diff --git a/app/assets/javascripts/admins/schools/index.js b/app/assets/javascripts/admins/schools/index.js new file mode 100644 index 000000000..20ea080fb --- /dev/null +++ b/app/assets/javascripts/admins/schools/index.js @@ -0,0 +1,4 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-schools-index-page').length > 0) { + } +}); \ No newline at end of file diff --git a/app/assets/javascripts/admins/users/index.js b/app/assets/javascripts/admins/users/index.js index 4d4f0f945..c7b8e5e6a 100644 --- a/app/assets/javascripts/admins/users/index.js +++ b/app/assets/javascripts/admins/users/index.js @@ -124,12 +124,12 @@ $(document).on('turbolinks:load', function(){ var $importUserForm = $importUserModal.find('form.admin-import-user-form') $importUserModal.on('show.bs.modal', function(){ + resetFileInputFunc($importUserModal.find('.upload-file-input')); $importUserModal.find('.file-names').html('选择文件'); $importUserModal.find('.upload-file-input').trigger('click'); }); - $importUserModal.find('.upload-file-input').on('change', function(e){ + $importUserModal.on('change', '.upload-file-input', function(e){ var file = $(this)[0].files[0]; - $importUserModal.find('.file-names').html(file ? file.name : '请选择文件'); }) @@ -175,7 +175,9 @@ $(document).on('turbolinks:load', function(){ $('body').mLoading('destroy'); $importUserModal.modal('hide'); - showMessageModal(buildResultMessage(data)); + showMessageModal(buildResultMessage(data), function(){ + window.location.reload(); + }); }, error: function(res){ $('body').mLoading('destroy'); diff --git a/app/assets/javascripts/common.js b/app/assets/javascripts/common.js new file mode 100644 index 000000000..8ff5c7bb7 --- /dev/null +++ b/app/assets/javascripts/common.js @@ -0,0 +1,67 @@ +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 customConfirm(opts){ + var okCallback = opts.ok; + var cancelCallback = opts.cancel; + + var defaultOpts = { + title: '提示', + buttons: { + ok: { + text: '确认', + btnClass: 'btn btn-primary', + action: okCallback + }, + cancel: { + text: '取消', + btnClass: 'btn btn-secondary', + action: cancelCallback + }, + } + } + return $.confirm($.extend({}, defaultOpts, opts)) +} \ 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/javascripts/jquery-confirm.min.js b/app/assets/javascripts/jquery-confirm.min.js new file mode 100755 index 000000000..2939dc60f --- /dev/null +++ b/app/assets/javascripts/jquery-confirm.min.js @@ -0,0 +1,10 @@ +/*! + * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/) + * Author: Boniface Pereira + * Website: www.craftpip.com + * Contact: hey@craftpip.com + * + * Copyright 2013-2019 jquery-confirm + * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) + */ +(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory);}else{if(typeof module==="object"&&module.exports){module.exports=function(root,jQuery){if(jQuery===undefined){if(typeof window!=="undefined"){jQuery=require("jquery");}else{jQuery=require("jquery")(root);}}factory(jQuery);return jQuery;};}else{factory(jQuery);}}}(function($){var w=window;$.fn.confirm=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}$(this).each(function(){var $this=$(this);if($this.attr("jc-attached")){console.warn("jConfirm has already been attached to this element ",$this[0]);return;}$this.on("click",function(e){e.preventDefault();var jcOption=$.extend({},options);if($this.attr("data-title")){jcOption.title=$this.attr("data-title");}if($this.attr("data-content")){jcOption.content=$this.attr("data-content");}if(typeof jcOption.buttons==="undefined"){jcOption.buttons={};}jcOption["$target"]=$this;if($this.attr("href")&&Object.keys(jcOption.buttons).length===0){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];jcOption.buttons=buttons;jcOption.buttons[firstBtn].action=function(){location.href=$this.attr("href");};}jcOption.closeIcon=false;var instance=$.confirm(jcOption);});$this.attr("jc-attached",true);});return $(this);};$.confirm=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!=="object"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});options.buttons=buttons;}return w.jconfirm(options);};$.alert=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!=="object"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];options.buttons[firstBtn]=buttons[firstBtn];}return w.jconfirm(options);};$.dialog=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false,closeIcon:function(){}};}options.buttons={};if(typeof options.closeIcon==="undefined"){options.closeIcon=function(){};}options.confirmKeys=[13];return w.jconfirm(options);};w.jconfirm=function(options){if(typeof options==="undefined"){options={};}var pluginOptions=$.extend(true,{},w.jconfirm.pluginDefaults);if(w.jconfirm.defaults){pluginOptions=$.extend(true,pluginOptions,w.jconfirm.defaults);}pluginOptions=$.extend(true,{},pluginOptions,options);var instance=new w.Jconfirm(pluginOptions);w.jconfirm.instances.push(instance);return instance;};w.Jconfirm=function(options){$.extend(this,options);this._init();};w.Jconfirm.prototype={_init:function(){var that=this;if(!w.jconfirm.instances.length){w.jconfirm.lastFocused=$("body").find(":focus");}this._id=Math.round(Math.random()*99999);this.contentParsed=$(document.createElement("div"));if(!this.lazyOpen){setTimeout(function(){that.open();},0);}},_buildHTML:function(){var that=this;this._parseAnimation(this.animation,"o");this._parseAnimation(this.closeAnimation,"c");this._parseBgDismissAnimation(this.backgroundDismissAnimation);this._parseColumnClass(this.columnClass);this._parseTheme(this.theme);this._parseType(this.type);var template=$(this.template);template.find(".jconfirm-box").addClass(this.animationParsed).addClass(this.backgroundDismissAnimationParsed).addClass(this.typeParsed);if(this.typeAnimated){template.find(".jconfirm-box").addClass("jconfirm-type-animated");}if(this.useBootstrap){template.find(".jc-bs3-row").addClass(this.bootstrapClasses.row);template.find(".jc-bs3-row").addClass("justify-content-md-center justify-content-sm-center justify-content-xs-center justify-content-lg-center");template.find(".jconfirm-box-container").addClass(this.columnClassParsed);if(this.containerFluid){template.find(".jc-bs3-container").addClass(this.bootstrapClasses.containerFluid);}else{template.find(".jc-bs3-container").addClass(this.bootstrapClasses.container);}}else{template.find(".jconfirm-box").css("width",this.boxWidth);}if(this.titleClass){template.find(".jconfirm-title-c").addClass(this.titleClass);}template.addClass(this.themeParsed);var ariaLabel="jconfirm-box"+this._id;template.find(".jconfirm-box").attr("aria-labelledby",ariaLabel).attr("tabindex",-1);template.find(".jconfirm-content").attr("id",ariaLabel);if(this.bgOpacity!==null){template.find(".jconfirm-bg").css("opacity",this.bgOpacity);}if(this.rtl){template.addClass("jconfirm-rtl");}this.$el=template.appendTo(this.container);this.$jconfirmBoxContainer=this.$el.find(".jconfirm-box-container");this.$jconfirmBox=this.$body=this.$el.find(".jconfirm-box");this.$jconfirmBg=this.$el.find(".jconfirm-bg");this.$title=this.$el.find(".jconfirm-title");this.$titleContainer=this.$el.find(".jconfirm-title-c");this.$content=this.$el.find("div.jconfirm-content");this.$contentPane=this.$el.find(".jconfirm-content-pane");this.$icon=this.$el.find(".jconfirm-icon-c");this.$closeIcon=this.$el.find(".jconfirm-closeIcon");this.$holder=this.$el.find(".jconfirm-holder");this.$btnc=this.$el.find(".jconfirm-buttons");this.$scrollPane=this.$el.find(".jconfirm-scrollpane");that.setStartingPoint();this._contentReady=$.Deferred();this._modalReady=$.Deferred();this.$holder.css({"padding-top":this.offsetTop,"padding-bottom":this.offsetBottom,});this.setTitle();this.setIcon();this._setButtons();this._parseContent();this.initDraggable();if(this.isAjax){this.showLoading(false);}$.when(this._contentReady,this._modalReady).then(function(){if(that.isAjaxLoading){setTimeout(function(){that.isAjaxLoading=false;that.setContent();that.setTitle();that.setIcon();setTimeout(function(){that.hideLoading(false);that._updateContentMaxHeight();},100);if(typeof that.onContentReady==="function"){that.onContentReady();}},50);}else{that._updateContentMaxHeight();that.setTitle();that.setIcon();if(typeof that.onContentReady==="function"){that.onContentReady();}}if(that.autoClose){that._startCountDown();}}).then(function(){that._watchContent();});if(this.animation==="none"){this.animationSpeed=1;this.animationBounce=1;}this.$body.css(this._getCSS(this.animationSpeed,this.animationBounce));this.$contentPane.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBg.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBoxContainer.css(this._getCSS(this.animationSpeed,1));},_typePrefix:"jconfirm-type-",typeParsed:"",_parseType:function(type){this.typeParsed=this._typePrefix+type;},setType:function(type){var oldClass=this.typeParsed;this._parseType(type);this.$jconfirmBox.removeClass(oldClass).addClass(this.typeParsed);},themeParsed:"",_themePrefix:"jconfirm-",setTheme:function(theme){var previous=this.theme;this.theme=theme||this.theme;this._parseTheme(this.theme);if(previous){this.$el.removeClass(previous);}this.$el.addClass(this.themeParsed);this.theme=theme;},_parseTheme:function(theme){var that=this;theme=theme.split(",");$.each(theme,function(k,a){if(a.indexOf(that._themePrefix)===-1){theme[k]=that._themePrefix+$.trim(a);}});this.themeParsed=theme.join(" ").toLowerCase();},backgroundDismissAnimationParsed:"",_bgDismissPrefix:"jconfirm-hilight-",_parseBgDismissAnimation:function(bgDismissAnimation){var animation=bgDismissAnimation.split(",");var that=this;$.each(animation,function(k,a){if(a.indexOf(that._bgDismissPrefix)===-1){animation[k]=that._bgDismissPrefix+$.trim(a);}});this.backgroundDismissAnimationParsed=animation.join(" ").toLowerCase();},animationParsed:"",closeAnimationParsed:"",_animationPrefix:"jconfirm-animation-",setAnimation:function(animation){this.animation=animation||this.animation;this._parseAnimation(this.animation,"o");},_parseAnimation:function(animation,which){which=which||"o";var animations=animation.split(",");var that=this;$.each(animations,function(k,a){if(a.indexOf(that._animationPrefix)===-1){animations[k]=that._animationPrefix+$.trim(a);}});var a_string=animations.join(" ").toLowerCase();if(which==="o"){this.animationParsed=a_string;}else{this.closeAnimationParsed=a_string;}return a_string;},setCloseAnimation:function(closeAnimation){this.closeAnimation=closeAnimation||this.closeAnimation;this._parseAnimation(this.closeAnimation,"c");},setAnimationSpeed:function(speed){this.animationSpeed=speed||this.animationSpeed;},columnClassParsed:"",setColumnClass:function(colClass){if(!this.useBootstrap){console.warn("cannot set columnClass, useBootstrap is set to false");return;}this.columnClass=colClass||this.columnClass;this._parseColumnClass(this.columnClass);this.$jconfirmBoxContainer.addClass(this.columnClassParsed);},_updateContentMaxHeight:function(){var height=$(window).height()-(this.$jconfirmBox.outerHeight()-this.$contentPane.outerHeight())-(this.offsetTop+this.offsetBottom);this.$contentPane.css({"max-height":height+"px"});},setBoxWidth:function(width){if(this.useBootstrap){console.warn("cannot set boxWidth, useBootstrap is set to true");return;}this.boxWidth=width;this.$jconfirmBox.css("width",width);},_parseColumnClass:function(colClass){colClass=colClass.toLowerCase();var p;switch(colClass){case"xl":case"xlarge":p="col-md-12";break;case"l":case"large":p="col-md-8 col-md-offset-2";break;case"m":case"medium":p="col-md-6 col-md-offset-3";break;case"s":case"small":p="col-md-4 col-md-offset-4";break;case"xs":case"xsmall":p="col-md-2 col-md-offset-5";break;default:p=colClass;}this.columnClassParsed=p;},initDraggable:function(){var that=this;var $t=this.$titleContainer;this.resetDrag();if(this.draggable){$t.on("mousedown",function(e){$t.addClass("jconfirm-hand");that.mouseX=e.clientX;that.mouseY=e.clientY;that.isDrag=true;});$(window).on("mousemove."+this._id,function(e){if(that.isDrag){that.movingX=e.clientX-that.mouseX+that.initialX;that.movingY=e.clientY-that.mouseY+that.initialY;that.setDrag();}});$(window).on("mouseup."+this._id,function(){$t.removeClass("jconfirm-hand");if(that.isDrag){that.isDrag=false;that.initialX=that.movingX;that.initialY=that.movingY;}});}},resetDrag:function(){this.isDrag=false;this.initialX=0;this.initialY=0;this.movingX=0;this.movingY=0;this.mouseX=0;this.mouseY=0;this.$jconfirmBoxContainer.css("transform","translate("+0+"px, "+0+"px)");},setDrag:function(){if(!this.draggable){return;}this.alignMiddle=false;var boxWidth=this.$jconfirmBox.outerWidth();var boxHeight=this.$jconfirmBox.outerHeight();var windowWidth=$(window).width();var windowHeight=$(window).height();var that=this;var dragUpdate=1;if(that.movingX%dragUpdate===0||that.movingY%dragUpdate===0){if(that.dragWindowBorder){var leftDistance=(windowWidth/2)-boxWidth/2;var topDistance=(windowHeight/2)-boxHeight/2;topDistance-=that.dragWindowGap;leftDistance-=that.dragWindowGap;if(leftDistance+that.movingX<0){that.movingX=-leftDistance;}else{if(leftDistance-that.movingX<0){that.movingX=leftDistance;}}if(topDistance+that.movingY<0){that.movingY=-topDistance;}else{if(topDistance-that.movingY<0){that.movingY=topDistance;}}}that.$jconfirmBoxContainer.css("transform","translate("+that.movingX+"px, "+that.movingY+"px)");}},_scrollTop:function(){if(typeof pageYOffset!=="undefined"){return pageYOffset;}else{var B=document.body;var D=document.documentElement;D=(D.clientHeight)?D:B;return D.scrollTop;}},_watchContent:function(){var that=this;if(this._timer){clearInterval(this._timer);}var prevContentHeight=0;this._timer=setInterval(function(){if(that.smoothContent){var contentHeight=that.$content.outerHeight()||0;if(contentHeight!==prevContentHeight){prevContentHeight=contentHeight;}var wh=$(window).height();var total=that.offsetTop+that.offsetBottom+that.$jconfirmBox.height()-that.$contentPane.height()+that.$content.height();if(total').html(that.buttons[key].text).addClass(that.buttons[key].btnClass).prop("disabled",that.buttons[key].isDisabled).css("display",that.buttons[key].isHidden?"none":"").click(function(e){e.preventDefault();var res=that.buttons[key].action.apply(that,[that.buttons[key]]);that.onAction.apply(that,[key,that.buttons[key]]);that._stopCountDown();if(typeof res==="undefined"||res){that.close();}});that.buttons[key].el=button_element;that.buttons[key].setText=function(text){button_element.html(text);};that.buttons[key].addClass=function(className){button_element.addClass(className);};that.buttons[key].removeClass=function(className){button_element.removeClass(className);};that.buttons[key].disable=function(){that.buttons[key].isDisabled=true;button_element.prop("disabled",true);};that.buttons[key].enable=function(){that.buttons[key].isDisabled=false;button_element.prop("disabled",false);};that.buttons[key].show=function(){that.buttons[key].isHidden=false;button_element.css("display","");};that.buttons[key].hide=function(){that.buttons[key].isHidden=true;button_element.css("display","none");};that["$_"+key]=that["$$"+key]=button_element;that.$btnc.append(button_element);});if(total_buttons===0){this.$btnc.hide();}if(this.closeIcon===null&&total_buttons===0){this.closeIcon=true;}if(this.closeIcon){if(this.closeIconClass){var closeHtml='';this.$closeIcon.html(closeHtml);}this.$closeIcon.click(function(e){e.preventDefault();var buttonName=false;var shouldClose=false;var str;if(typeof that.closeIcon==="function"){str=that.closeIcon();}else{str=that.closeIcon;}if(typeof str==="string"&&typeof that.buttons[str]!=="undefined"){buttonName=str;shouldClose=false;}else{if(typeof str==="undefined"||!!(str)===true){shouldClose=true;}else{shouldClose=false;}}if(buttonName){var btnResponse=that.buttons[buttonName].action.apply(that);shouldClose=(typeof btnResponse==="undefined")||!!(btnResponse);}if(shouldClose){that.close();}});this.$closeIcon.show();}else{this.$closeIcon.hide();}},setTitle:function(string,force){force=force||false;if(typeof string!=="undefined"){if(typeof string==="string"){this.title=string;}else{if(typeof string==="function"){if(typeof string.promise==="function"){console.error("Promise was returned from title function, this is not supported.");}var response=string();if(typeof response==="string"){this.title=response;}else{this.title=false;}}else{this.title=false;}}}if(this.isAjaxLoading&&!force){return;}this.$title.html(this.title||"");this.updateTitleContainer();},setIcon:function(iconClass,force){force=force||false;if(typeof iconClass!=="undefined"){if(typeof iconClass==="string"){this.icon=iconClass;}else{if(typeof iconClass==="function"){var response=iconClass();if(typeof response==="string"){this.icon=response;}else{this.icon=false;}}else{this.icon=false;}}}if(this.isAjaxLoading&&!force){return;}this.$icon.html(this.icon?'':"");this.updateTitleContainer();},updateTitleContainer:function(){if(!this.title&&!this.icon){this.$titleContainer.hide();}else{this.$titleContainer.show();}},setContentPrepend:function(content,force){if(!content){return;}this.contentParsed.prepend(content);},setContentAppend:function(content){if(!content){return;}this.contentParsed.append(content);},setContent:function(content,force){force=!!force;var that=this;if(content){this.contentParsed.html("").append(content);}if(this.isAjaxLoading&&!force){return;}this.$content.html("");this.$content.append(this.contentParsed);setTimeout(function(){that.$body.find("input[autofocus]:visible:first").focus();},100);},loadingSpinner:false,showLoading:function(disableButtons){this.loadingSpinner=true;this.$jconfirmBox.addClass("loading");if(disableButtons){this.$btnc.find("button").prop("disabled",true);}},hideLoading:function(enableButtons){this.loadingSpinner=false;this.$jconfirmBox.removeClass("loading");if(enableButtons){this.$btnc.find("button").prop("disabled",false);}},ajaxResponse:false,contentParsed:"",isAjax:false,isAjaxLoading:false,_parseContent:function(){var that=this;var e=" ";if(typeof this.content==="function"){var res=this.content.apply(this);if(typeof res==="string"){this.content=res;}else{if(typeof res==="object"&&typeof res.always==="function"){this.isAjax=true;this.isAjaxLoading=true;res.always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});this.content=e;}else{this.content=e;}}}if(typeof this.content==="string"&&this.content.substr(0,4).toLowerCase()==="url:"){this.isAjax=true;this.isAjaxLoading=true;var u=this.content.substring(4,this.content.length);$.get(u).done(function(html){that.contentParsed.html(html);}).always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});}if(!this.content){this.content=e;}if(!this.isAjax){this.contentParsed.html(this.content);this.setContent();that._contentReady.resolve();}},_stopCountDown:function(){clearInterval(this.autoCloseInterval);if(this.$cd){this.$cd.remove();}},_startCountDown:function(){var that=this;var opt=this.autoClose.split("|");if(opt.length!==2){console.error("Invalid option for autoClose. example 'close|10000'");return false;}var button_key=opt[0];var time=parseInt(opt[1]);if(typeof this.buttons[button_key]==="undefined"){console.error("Invalid button key '"+button_key+"' for autoClose");return false;}var seconds=Math.ceil(time/1000);this.$cd=$(' ('+seconds+")").appendTo(this["$_"+button_key]);this.autoCloseInterval=setInterval(function(){that.$cd.html(" ("+(seconds-=1)+") ");if(seconds<=0){that["$$"+button_key].trigger("click");that._stopCountDown();}},1000);},_getKey:function(key){switch(key){case 192:return"tilde";case 13:return"enter";case 16:return"shift";case 9:return"tab";case 20:return"capslock";case 17:return"ctrl";case 91:return"win";case 18:return"alt";case 27:return"esc";case 32:return"space";}var initial=String.fromCharCode(key);if(/^[A-z0-9]+$/.test(initial)){return initial.toLowerCase();}else{return false;}},reactOnKey:function(e){var that=this;var a=$(".jconfirm");if(a.eq(a.length-1)[0]!==this.$el[0]){return false;}var key=e.which;if(this.$content.find(":input").is(":focus")&&/13|32/.test(key)){return false;}var keyChar=this._getKey(key);if(keyChar==="esc"&&this.escapeKey){if(this.escapeKey===true){this.$scrollPane.trigger("click");}else{if(typeof this.escapeKey==="string"||typeof this.escapeKey==="function"){var buttonKey;if(typeof this.escapeKey==="function"){buttonKey=this.escapeKey();}else{buttonKey=this.escapeKey;}if(buttonKey){if(typeof this.buttons[buttonKey]==="undefined"){console.warn("Invalid escapeKey, no buttons found with key "+buttonKey);}else{this["$_"+buttonKey].trigger("click");}}}}}$.each(this.buttons,function(key,button){if(button.keys.indexOf(keyChar)!==-1){that["$_"+key].trigger("click");}});},setDialogCenter:function(){console.info("setDialogCenter is deprecated, dialogs are centered with CSS3 tables");},_unwatchContent:function(){clearInterval(this._timer);},close:function(onClosePayload){var that=this;if(typeof this.onClose==="function"){this.onClose(onClosePayload);}this._unwatchContent();$(window).unbind("resize."+this._id);$(window).unbind("keyup."+this._id);$(window).unbind("jcKeyDown."+this._id);if(this.draggable){$(window).unbind("mousemove."+this._id);$(window).unbind("mouseup."+this._id);this.$titleContainer.unbind("mousedown");}that.$el.removeClass(that.loadedClass);$("body").removeClass("jconfirm-no-scroll-"+that._id);that.$jconfirmBoxContainer.removeClass("jconfirm-no-transition");setTimeout(function(){that.$body.addClass(that.closeAnimationParsed);that.$jconfirmBg.addClass("jconfirm-bg-h");var closeTimer=(that.closeAnimation==="none")?1:that.animationSpeed;setTimeout(function(){that.$el.remove();var l=w.jconfirm.instances;var i=w.jconfirm.instances.length-1;for(i;i>=0;i--){if(w.jconfirm.instances[i]._id===that._id){w.jconfirm.instances.splice(i,1);}}if(!w.jconfirm.instances.length){if(that.scrollToPreviousElement&&w.jconfirm.lastFocused&&w.jconfirm.lastFocused.length&&$.contains(document,w.jconfirm.lastFocused[0])){var $lf=w.jconfirm.lastFocused;if(that.scrollToPreviousElementAnimate){var st=$(window).scrollTop();var ot=w.jconfirm.lastFocused.offset().top;var wh=$(window).height();if(!(ot>st&&ot<(st+wh))){var scrollTo=(ot-Math.round((wh/3)));$("html, body").animate({scrollTop:scrollTo},that.animationSpeed,"swing",function(){$lf.focus();});}else{$lf.focus();}}else{$lf.focus();}w.jconfirm.lastFocused=false;}}if(typeof that.onDestroy==="function"){that.onDestroy();}},closeTimer*0.4);},50);return true;},open:function(){if(this.isOpen()){return false;}this._buildHTML();this._bindEvents();this._open();return true;},setStartingPoint:function(){var el=false;if(this.animateFromElement!==true&&this.animateFromElement){el=this.animateFromElement;w.jconfirm.lastClicked=false;}else{if(w.jconfirm.lastClicked&&this.animateFromElement===true){el=w.jconfirm.lastClicked;w.jconfirm.lastClicked=false;}else{return false;}}if(!el){return false;}var offset=el.offset();var iTop=el.outerHeight()/2;var iLeft=el.outerWidth()/2;iTop-=this.$jconfirmBox.outerHeight()/2;iLeft-=this.$jconfirmBox.outerWidth()/2;var sourceTop=offset.top+iTop;sourceTop=sourceTop-this._scrollTop();var sourceLeft=offset.left+iLeft;var wh=$(window).height()/2;var ww=$(window).width()/2;var targetH=wh-this.$jconfirmBox.outerHeight()/2;var targetW=ww-this.$jconfirmBox.outerWidth()/2;sourceTop-=targetH;sourceLeft-=targetW;if(Math.abs(sourceTop)>wh||Math.abs(sourceLeft)>ww){return false;}this.$jconfirmBoxContainer.css("transform","translate("+sourceLeft+"px, "+sourceTop+"px)");},_open:function(){var that=this;if(typeof that.onOpenBefore==="function"){that.onOpenBefore();}this.$body.removeClass(this.animationParsed);this.$jconfirmBg.removeClass("jconfirm-bg-h");this.$body.focus();that.$jconfirmBoxContainer.css("transform","translate("+0+"px, "+0+"px)");setTimeout(function(){that.$body.css(that._getCSS(that.animationSpeed,1));that.$body.css({"transition-property":that.$body.css("transition-property")+", margin"});that.$jconfirmBoxContainer.addClass("jconfirm-no-transition");that._modalReady.resolve();if(typeof that.onOpen==="function"){that.onOpen();}that.$el.addClass(that.loadedClass);},this.animationSpeed);},loadedClass:"jconfirm-open",isClosed:function(){return !this.$el||this.$el.parent().length===0;},isOpen:function(){return !this.isClosed();},toggle:function(){if(!this.isOpen()){this.open();}else{this.close();}}};w.jconfirm.instances=[];w.jconfirm.lastFocused=false;w.jconfirm.pluginDefaults={template:'
',title:"Hello",titleClass:"",type:"default",typeAnimated:true,draggable:true,dragWindowGap:15,dragWindowBorder:true,animateFromElement:true,alignMiddle:true,smoothContent:true,content:"Are you sure to continue?",buttons:{},defaultButtons:{ok:{action:function(){}},close:{action:function(){}}},contentLoaded:function(){},icon:"",lazyOpen:false,bgOpacity:null,theme:"light",animation:"scale",closeAnimation:"scale",animationSpeed:400,animationBounce:1,escapeKey:true,rtl:false,container:"body",containerFluid:false,backgroundDismiss:false,backgroundDismissAnimation:"shake",autoClose:false,closeIcon:null,closeIconClass:false,watchInterval:100,columnClass:"col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1",boxWidth:"50%",scrollToPreviousElement:true,scrollToPreviousElementAnimate:true,useBootstrap:true,offsetTop:40,offsetBottom:40,bootstrapClasses:{container:"container",containerFluid:"container-fluid",row:"row"},onContentReady:function(){},onOpenBefore:function(){},onOpen:function(){},onClose:function(){},onDestroy:function(){},onAction:function(){}};var keyDown=false;$(window).on("keydown",function(e){if(!keyDown){var $target=$(e.target);var pass=false;if($target.closest(".jconfirm-box").length){pass=true;}if(pass){$(window).trigger("jcKeyDown");}keyDown=true;}});$(window).on("keyup",function(){keyDown=false;});w.jconfirm.lastClicked=false;$(document).on("mousedown","button, a, [jc-source]",function(){w.jconfirm.lastClicked=$(this);});})); \ No newline at end of file diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index 30fd635a6..67947ce2c 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -6,7 +6,11 @@ @import "bootstrap-datepicker"; @import "bootstrap-datepicker.standalone"; @import "jquery.mloading"; -@import "lib/codemirror"; +@import "jquery-confirm.min"; + +@import "codemirror/lib/codemirror"; +@import "editormd/css/editormd.min"; +@import "dragula/dragula"; @import "common"; @import "admins/*"; @@ -47,4 +51,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/common.scss b/app/assets/stylesheets/admins/common.scss index 56b286981..adad72997 100644 --- a/app/assets/stylesheets/admins/common.scss +++ b/app/assets/stylesheets/admins/common.scss @@ -110,5 +110,11 @@ .CodeMirror { border: 1px solid #ced4da; } + + .batch-action-container { + margin-bottom: -15px; + padding: 10px 20px 0; + background: #fff; + } } 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/admins/schools.scss b/app/assets/stylesheets/admins/schools.scss new file mode 100644 index 000000000..8dff1eaff --- /dev/null +++ b/app/assets/stylesheets/admins/schools.scss @@ -0,0 +1,3 @@ +.admins-schools-index-page { + +} \ 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/assets/stylesheets/jquery-confirm.min.css b/app/assets/stylesheets/jquery-confirm.min.css new file mode 100755 index 000000000..b66d20545 --- /dev/null +++ b/app/assets/stylesheets/jquery-confirm.min.css @@ -0,0 +1,9 @@ +/*! + * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/) + * Author: boniface pereira + * Website: www.craftpip.com + * Contact: hey@craftpip.com + * + * Copyright 2013-2019 jquery-confirm + * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) + */@-webkit-keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes jconfirm-spin{from{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}body[class*=jconfirm-no-scroll-]{overflow:hidden!important}.jconfirm{position:fixed;top:0;left:0;right:0;bottom:0;z-index:99999999;font-family:inherit;overflow:hidden}.jconfirm .jconfirm-bg{position:fixed;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .4s;transition:opacity .4s}.jconfirm .jconfirm-bg.jconfirm-bg-h{opacity:0!important}.jconfirm .jconfirm-scrollpane{-webkit-perspective:500px;perspective:500px;-webkit-perspective-origin:center;perspective-origin:center;display:table;width:100%;height:100%}.jconfirm .jconfirm-row{display:table-row;width:100%}.jconfirm .jconfirm-cell{display:table-cell;vertical-align:middle}.jconfirm .jconfirm-holder{max-height:100%;padding:50px 0}.jconfirm .jconfirm-box-container{-webkit-transition:-webkit-transform;transition:-webkit-transform;transition:transform;transition:transform,-webkit-transform}.jconfirm .jconfirm-box-container.jconfirm-no-transition{-webkit-transition:none!important;transition:none!important}.jconfirm .jconfirm-box{background:white;border-radius:4px;position:relative;outline:0;padding:15px 15px 0;overflow:hidden;margin-left:auto;margin-right:auto}@-webkit-keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@keyframes type-blue{1%,100%{border-color:#3498db}50%{border-color:#5faee3}}@-webkit-keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@keyframes type-green{1%,100%{border-color:#2ecc71}50%{border-color:#54d98c}}@-webkit-keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@keyframes type-red{1%,100%{border-color:#e74c3c}50%{border-color:#ed7669}}@-webkit-keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@keyframes type-orange{1%,100%{border-color:#f1c40f}50%{border-color:#f4d03f}}@-webkit-keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@keyframes type-purple{1%,100%{border-color:#9b59b6}50%{border-color:#b07cc6}}@-webkit-keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}@keyframes type-dark{1%,100%{border-color:#34495e}50%{border-color:#46627f}}.jconfirm .jconfirm-box.jconfirm-type-animated{-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.jconfirm .jconfirm-box.jconfirm-type-blue{border-top:solid 7px #3498db;-webkit-animation-name:type-blue;animation-name:type-blue}.jconfirm .jconfirm-box.jconfirm-type-green{border-top:solid 7px #2ecc71;-webkit-animation-name:type-green;animation-name:type-green}.jconfirm .jconfirm-box.jconfirm-type-red{border-top:solid 7px #e74c3c;-webkit-animation-name:type-red;animation-name:type-red}.jconfirm .jconfirm-box.jconfirm-type-orange{border-top:solid 7px #f1c40f;-webkit-animation-name:type-orange;animation-name:type-orange}.jconfirm .jconfirm-box.jconfirm-type-purple{border-top:solid 7px #9b59b6;-webkit-animation-name:type-purple;animation-name:type-purple}.jconfirm .jconfirm-box.jconfirm-type-dark{border-top:solid 7px #34495e;-webkit-animation-name:type-dark;animation-name:type-dark}.jconfirm .jconfirm-box.loading{height:120px}.jconfirm .jconfirm-box.loading:before{content:'';position:absolute;left:0;background:white;right:0;top:0;bottom:0;border-radius:10px;z-index:1}.jconfirm .jconfirm-box.loading:after{opacity:.6;content:'';height:30px;width:30px;border:solid 3px transparent;position:absolute;left:50%;margin-left:-15px;border-radius:50%;-webkit-animation:jconfirm-spin 1s infinite linear;animation:jconfirm-spin 1s infinite linear;border-bottom-color:dodgerblue;top:50%;margin-top:-15px;z-index:2}.jconfirm .jconfirm-box div.jconfirm-closeIcon{height:20px;width:20px;position:absolute;top:10px;right:10px;cursor:pointer;opacity:.6;text-align:center;font-size:27px!important;line-height:14px!important;display:none;z-index:1}.jconfirm .jconfirm-box div.jconfirm-closeIcon:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-closeIcon .fa{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi{font-size:16px}.jconfirm .jconfirm-box div.jconfirm-closeIcon:hover{opacity:1}.jconfirm .jconfirm-box div.jconfirm-title-c{display:block;font-size:22px;line-height:20px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:default;padding-bottom:15px}.jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand{cursor:move}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{font-size:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i{vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;font-size:inherit;font-family:inherit;display:inline-block;vertical-align:middle}.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty{display:none}.jconfirm .jconfirm-box div.jconfirm-content-pane{margin-bottom:15px;height:auto;-webkit-transition:height .4s ease-in;transition:height .4s ease-in;display:inline-block;width:100%;position:relative;overflow-x:hidden;overflow-y:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane.no-scroll{overflow-y:hidden}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar{width:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-track{background:rgba(0,0,0,0.1)}.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-thumb{background:#666;border-radius:3px}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content{overflow:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img{max-width:100%;height:auto}.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty{display:none}.jconfirm .jconfirm-box .jconfirm-buttons{padding-bottom:11px}.jconfirm .jconfirm-box .jconfirm-buttons>button{margin-bottom:4px;margin-left:2px;margin-right:2px}.jconfirm .jconfirm-box .jconfirm-buttons button{display:inline-block;padding:6px 12px;font-size:14px;font-weight:400;line-height:1.42857143;text-align:center;white-space:nowrap;vertical-align:middle;-ms-touch-action:manipulation;touch-action:manipulation;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;border-radius:4px;min-height:1em;-webkit-transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease;transition:opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease,-webkit-box-shadow .1s ease;-webkit-tap-highlight-color:transparent;border:0;background-image:none}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue{background-color:#3498db;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover{background-color:#2980b9;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green{background-color:#2ecc71;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover{background-color:#27ae60;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red{background-color:#e74c3c;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover{background-color:#c0392b;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange{background-color:#f1c40f;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover{background-color:#f39c12;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default{background-color:#ecf0f1;color:#000;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover{background-color:#bdc3c7;color:#000}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple{background-color:#9b59b6;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover{background-color:#8e44ad;color:#FFF}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark{background-color:#34495e;color:#FFF;text-shadow:none;-webkit-transition:background .2s;transition:background .2s}.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover{background-color:#2c3e50;color:#FFF}.jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c{color:#e74c3c!important}.jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c{color:#3498db!important}.jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c{color:#2ecc71!important}.jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c{color:#9b59b6!important}.jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c{color:#f1c40f!important}.jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c{color:#34495e!important}.jconfirm .jconfirm-clear{clear:both}.jconfirm.jconfirm-rtl{direction:rtl}.jconfirm.jconfirm-rtl div.jconfirm-closeIcon{left:5px;right:auto}.jconfirm.jconfirm-white .jconfirm-bg,.jconfirm.jconfirm-light .jconfirm-bg{background-color:#444;opacity:.2}.jconfirm.jconfirm-white .jconfirm-box,.jconfirm.jconfirm-light .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);border-radius:5px}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#333}.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#ddd}.jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-black .jconfirm-bg,.jconfirm.jconfirm-dark .jconfirm-bg{background-color:darkslategray;opacity:.4}.jconfirm.jconfirm-black .jconfirm-box,.jconfirm.jconfirm-dark .jconfirm-box{-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.2);box-shadow:0 2px 6px rgba(0,0,0,0.2);background:#444;border-radius:5px;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons{float:right}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button{border:0;background-image:none;text-transform:uppercase;font-size:14px;font-weight:bold;text-shadow:none;-webkit-transition:background .1s;transition:background .1s;color:white}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default{-webkit-box-shadow:none;box-shadow:none;color:#fff;background:0}.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover,.jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover{background:#666}.jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c,.jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake{-webkit-animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:shake .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow{-webkit-animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;animation:glow .82s cubic-bezier(0.36,0.07,0.19,0.97) both;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}@-webkit-keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@keyframes shake{10%,90%{-webkit-transform:translate3d(-2px,0,0);transform:translate3d(-2px,0,0)}20%,80%{-webkit-transform:translate3d(4px,0,0);transform:translate3d(4px,0,0)}30%,50%,70%{-webkit-transform:translate3d(-8px,0,0);transform:translate3d(-8px,0,0)}40%,60%{-webkit-transform:translate3d(8px,0,0);transform:translate3d(8px,0,0)}}@-webkit-keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}@keyframes glow{0%,100%{-webkit-box-shadow:0 0 0 red;box-shadow:0 0 0 red}50%{-webkit-box-shadow:0 0 30px red;box-shadow:0 0 30px red}}.jconfirm{-webkit-perspective:400px;perspective:400px}.jconfirm .jconfirm-box{opacity:1;-webkit-transition-property:all;transition-property:all}.jconfirm .jconfirm-box.jconfirm-animation-top,.jconfirm .jconfirm-box.jconfirm-animation-left,.jconfirm .jconfirm-box.jconfirm-animation-right,.jconfirm .jconfirm-box.jconfirm-animation-bottom,.jconfirm .jconfirm-box.jconfirm-animation-opacity,.jconfirm .jconfirm-box.jconfirm-animation-zoom,.jconfirm .jconfirm-box.jconfirm-animation-scale,.jconfirm .jconfirm-box.jconfirm-animation-none,.jconfirm .jconfirm-box.jconfirm-animation-rotate,.jconfirm .jconfirm-box.jconfirm-animation-rotatex,.jconfirm .jconfirm-box.jconfirm-animation-rotatey,.jconfirm .jconfirm-box.jconfirm-animation-scaley,.jconfirm .jconfirm-box.jconfirm-animation-scalex{opacity:0}.jconfirm .jconfirm-box.jconfirm-animation-rotate{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.jconfirm .jconfirm-box.jconfirm-animation-rotatex{-webkit-transform:rotateX(90deg);transform:rotateX(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatexr{-webkit-transform:rotateX(-90deg);transform:rotateX(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotatey{-webkit-transform:rotatey(90deg);transform:rotatey(90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-rotateyr{-webkit-transform:rotatey(-90deg);transform:rotatey(-90deg);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scaley{-webkit-transform:scaley(1.5);transform:scaley(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-scalex{-webkit-transform:scalex(1.5);transform:scalex(1.5);-webkit-transform-origin:center;transform-origin:center}.jconfirm .jconfirm-box.jconfirm-animation-top{-webkit-transform:translate(0px,-100px);transform:translate(0px,-100px)}.jconfirm .jconfirm-box.jconfirm-animation-left{-webkit-transform:translate(-100px,0px);transform:translate(-100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-right{-webkit-transform:translate(100px,0px);transform:translate(100px,0px)}.jconfirm .jconfirm-box.jconfirm-animation-bottom{-webkit-transform:translate(0px,100px);transform:translate(0px,100px)}.jconfirm .jconfirm-box.jconfirm-animation-zoom{-webkit-transform:scale(1.2);transform:scale(1.2)}.jconfirm .jconfirm-box.jconfirm-animation-scale{-webkit-transform:scale(0.5);transform:scale(0.5)}.jconfirm .jconfirm-box.jconfirm-animation-none{visibility:hidden}.jconfirm.jconfirm-supervan .jconfirm-bg{background-color:rgba(54,70,93,0.95)}.jconfirm.jconfirm-supervan .jconfirm-box{background-color:transparent}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple{border:0}.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark{border:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon{color:white}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c{text-align:center;color:white;font-size:28px;font-weight:normal}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c>*{padding-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane{margin-bottom:25px}.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content{text-align:center;color:white}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button{font-size:16px;border-radius:2px;background:#303f53;text-shadow:none;border:0;color:white;padding:10px;min-width:100px}.jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-material .jconfirm-bg{background-color:rgba(0,0,0,0.67)}.jconfirm.jconfirm-material .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 25px 10px 25px}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold}.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons{text-align:right}.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button{text-transform:uppercase;font-weight:500}.jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-bootstrap .jconfirm-bg{background-color:rgba(0,0,0,0.21)}.jconfirm.jconfirm-bootstrap .jconfirm-box{background-color:white;-webkit-box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);box-shadow:0 3px 8px 0 rgba(0,0,0,0.2);border:solid 1px rgba(0,0,0,0.4);padding:15px 0 0}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{margin-right:8px;margin-left:0}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87)}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:22px;font-weight:bold;padding-left:15px;padding-right:15px}.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content{color:rgba(0,0,0,0.87);padding:0 15px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons{text-align:right;padding:10px;margin:-5px 0 0;border-top:solid 1px #ddd;overflow:hidden;border-radius:0 0 4px 4px}.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button{font-weight:500}.jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c{margin-left:8px;margin-right:0}.jconfirm.jconfirm-modern .jconfirm-bg{background-color:slategray;opacity:.6}.jconfirm.jconfirm-modern .jconfirm-box{background-color:white;-webkit-box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);box-shadow:0 7px 8px -4px rgba(0,0,0,0.2),0 13px 19px 2px rgba(0,0,0,0.14),0 5px 24px 4px rgba(0,0,0,0.12);padding:30px 30px 15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon{color:rgba(0,0,0,0.87);top:15px;right:15px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c{color:rgba(0,0,0,0.87);font-size:24px;font-weight:bold;text-align:center;margin-bottom:10px}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c{-webkit-transition:-webkit-transform .5s;transition:-webkit-transform .5s;transition:transform .5s;transition:transform .5s,-webkit-transform .5s;-webkit-transform:scale(0);transform:scale(0);display:block;margin-right:0;margin-left:0;margin-bottom:10px;font-size:69px;color:#aaa}.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content{text-align:center;font-size:15px;color:#777;margin-bottom:25px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons{text-align:center}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button{font-weight:bold;text-transform:uppercase;-webkit-transition:background .1s;transition:background .1s;padding:10px 20px}.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button+button{margin-left:4px}.jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c{-webkit-transform:scale(1);transform:scale(1)} \ No newline at end of file diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index 3e90f0ef6..9106d1474 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -114,6 +114,35 @@ class AccountsController < ApplicationController end end + def successful_authentication(user) + uid_logger("Successful authentication start: '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}") + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + + set_autologin_cookie(user) + UserAction.create(:action_id => user.try(:id), :action_type => "Login", :user_id => user.try(:id), :ip => request.remote_ip) + user.update_column(:last_login_on, Time.now) + # 注册完成后有一天的试用申请(先去掉) + # UserDayCertification.create(user_id: user.id, status: 1) + end + + # def set_autologin_cookie(user) + # token = Token.get_or_create_permanent_login_token(user, "autologin") + # cookie_options = { + # :value => token.value, + # :expires => 1.month.from_now, + # :path => '/', + # :secure => false, + # :httponly => true + # } + # if edu_setting('cookie_domain').present? + # cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) + # end + # cookies[autologin_cookie_name] = cookie_options + # logger.info("cookies is #{cookies}") + # end + def logout UserAction.create(action_id: User.current.id, action_type: "Logout", user_id: User.current.id, :ip => request.remote_ip) session[:user_id] = nil 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 new file mode 100644 index 000000000..458721e34 --- /dev/null +++ b/app/controllers/admins/department_applies_controller.rb @@ -0,0 +1,106 @@ +class Admins::DepartmentAppliesController < Admins::BaseController + + before_action :get_apply,only:[:agree,:destroy] + + def index + params[:status] ||= 0 + params[:sort_by] = params[:sort_by].presence || 'created_at' + params[:sort_direction] = params[:sort_direction].presence || 'desc' + applies = Admins::DepartmentApplyQuery.call(params) + @depart_applies = paginate applies.preload(:school,user: :user_extension) + end + + def agree + ActiveRecord::Base.transaction do + @depart_apply.update_attribute("status",1) + @depart_apply&.applied_messages&.update_all(status:1) + @depart_apply&.department&.update_attribute("is_auth",1) + @depart_apply&.user&.user_extension&.update_attribute("department_id",@depart_apply.department_id) + render_success_js + end + end + + 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 + 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: apply_add.user_id, + trigger_user_id: 0, + container_id: apply_add.id, + container_type: 'ApplyAddDepartment', + belong_container_id: apply_add&.department&.school_id, + belong_container_type: "School", + tiding_type: "System", + status: 3, + extra: extra + } + Tiding.create(tiding_params) + + 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.destroy + render_success_js + end + end + + private + + def get_apply + @depart_apply = ApplyAddDepartment.find_by(id:params[:id]) + 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/identity_authentications_controller.rb b/app/controllers/admins/identity_authentications_controller.rb index 90758ace8..bae441b24 100644 --- a/app/controllers/admins/identity_authentications_controller.rb +++ b/app/controllers/admins/identity_authentications_controller.rb @@ -1,6 +1,7 @@ class Admins::IdentityAuthenticationsController < Admins::BaseController def index params[:status] ||= 'pending' + params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc' applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 1)) @@ -18,6 +19,24 @@ class Admins::IdentityAuthenticationsController < Admins::BaseController render_success_js end + def batch_agree + ApplyUserAuthentication.real_name_auth.where(id: params[:ids]).each do |apply| + begin + Admins::IdentityAuths::AgreeApplyService.call(apply) + rescue => e + Util.logger_error(e) + end + end + + render_ok + end + + def revoke + Admins::IdentityAuths::RevokeApplyService.call(current_apply) + + render_success_js + end + private def current_apply 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/professional_authentications_controller.rb b/app/controllers/admins/professional_authentications_controller.rb index 327ee696c..5c13b8250 100644 --- a/app/controllers/admins/professional_authentications_controller.rb +++ b/app/controllers/admins/professional_authentications_controller.rb @@ -1,6 +1,7 @@ class Admins::ProfessionalAuthenticationsController < Admins::BaseController def index params[:status] ||= 'pending' + params[:sort_direction] = params[:status] == 'pending' ? 'asc' : 'desc' applies = Admins::ApplyUserAuthenticationQuery.call(params.merge(type: 2)) @@ -18,6 +19,23 @@ class Admins::ProfessionalAuthenticationsController < Admins::BaseController render_success_js end + def batch_agree + ApplyUserAuthentication.professional_auth.where(id: params[:ids]).each do |apply| + begin + Admins::ProfessionalAuths::AgreeApplyService.call(apply) + rescue => e + Util.logger_error(e) + end + end + + render_ok + end + + def revoke + Admins::ProfessionalAuths::RevokeApplyService.call(current_apply) + render_success_js + end + private def current_apply diff --git a/app/controllers/admins/schools_controller.rb b/app/controllers/admins/schools_controller.rb new file mode 100644 index 000000000..8c4f1d59e --- /dev/null +++ b/app/controllers/admins/schools_controller.rb @@ -0,0 +1,30 @@ +class Admins::SchoolsController < Admins::BaseController + def index + params[:sort_by] ||= 'created_at' + params[:sort_direction] ||= 'desc' + + schools = Admins::SchoolQuery.call(params) + + @schools = paginate schools + + school_ids = @schools.map(&:id) + @department_count = Department.where(school_id: school_ids).group(:school_id).count + end + + def destroy + users = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id }) + + ActiveRecord::Base.transaction do + users.update_all(profile_completed: false) + current_school.destroy! + end + + render_delete_success + end + + private + + def current_school + @_current_school ||= School.find(params[:id]) + 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 cde4db414..f42ed6cce 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base #before_action :check_account DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" helper_method :current_user @@ -46,6 +47,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:忘记密码 @@ -234,6 +242,20 @@ class ApplicationController < ActionController::Base User.current = find_current_user uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + # 开放课程通过链接访问的用户 + if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? + content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" + + if Digest::MD5.hexdigest(content) == params[:chinaoocKey] + user = open_class_user + if user + start_user_session(user) + set_autologin_cookie(user) + end + User.current = user + end + end + if !User.current.logged? && Rails.env.development? User.current = User.find 1 end @@ -241,7 +263,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' @@ -581,4 +603,43 @@ class ApplicationController < ActionController::Base def set_export_cookies cookies[:fileDownload] = true end + + def set_autologin_cookie(user) + token = Token.get_or_create_permanent_login_token(user, "autologin") + cookie_options = { + :value => token.value, + :expires => 1.month.from_now, + :path => '/', + :secure => false, + :httponly => true + } + if edu_setting('cookie_domain').present? + cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) + end + cookies[autologin_cookie_name] = cookie_options + logger.info("cookies is #{cookies}") + end + + # 149课程的评审用户数据创建(包含创建课堂学生) + def open_class_user + user = User.find_by(login: "OpenClassUser") + unless user + ActiveRecord::Base.transaction do + user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程", + nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0, + password: "12345678", phone: "11122223333", profile_completed: 1} + user = User.create!(user_params) + + UserExtension.create!(user_id: user.id, gender: 0, school_id: 3396, :identity => 1, :student_id => "openclassuser") # 3396 + + subject = Subject.find_by(id: 149) + if subject + subject.courses.each do |course| + CourseMember.create!(course_id: course.id, role: 3, user_id: user.id) if !course.course_members.exists?(user_id: user.id) + end + end + end + end + user + end end 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/colleges_controller.rb b/app/controllers/colleges_controller.rb index 66d327649..f869e9ec6 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -40,8 +40,8 @@ class CollegesController < ApplicationController def teachers @teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count, - (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND m.user_id=users.id AND c.is_delete = 0) as course_count - FROM `users`, user_extensions ue where users.id=ue.user_id and ue.identity=0 and ue.school_id=#{current_school.id} ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") + (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.user_id=users.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND c.is_delete = 0) as course_count + FROM `users`, user_extensions ue where ue.school_id=#{current_school.id} and users.id=ue.user_id and ue.identity=0 ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") # ).order("publish_shixun_count desc, experience desc").limit(10) @teachers = @teachers.map do |teacher| diff --git a/app/controllers/commons_controller.rb b/app/controllers/commons_controller.rb index 0c0fe79af..bcb0fa45a 100644 --- a/app/controllers/commons_controller.rb +++ b/app/controllers/commons_controller.rb @@ -51,7 +51,8 @@ class CommonsController < ApplicationController 200 end when 'journals_for_message' - if current_user.course_identity(@object.jour.course) >= Course::STUDENT && @object.user != current_user + course = @object&.jour_type.to_s == "StudentWorksScore" ? @object.jour&.student_work&.homework_common&.course : @object.jour&.course + if current_user.course_identity(course) >= Course::STUDENT && @object.user != current_user 403 else 200 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/concerns/paginate_helper.rb b/app/controllers/concerns/paginate_helper.rb index bbe84a348..7233adebf 100644 --- a/app/controllers/concerns/paginate_helper.rb +++ b/app/controllers/concerns/paginate_helper.rb @@ -3,6 +3,10 @@ module PaginateHelper page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : opts[:per_page] || 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file 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 b10147462..d2c9f88d2 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -27,15 +27,16 @@ class CoursesController < ApplicationController :attahcment_category_list,:export_member_scores_excel, :duplicate_course, :switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course, :informs, :update_informs, :online_learning, :update_task_position, :tasks_list, - :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs] + :join_excellent_course, :export_couser_info, :export_member_act_score, :new_informs, :delete_informs] before_action :user_course_identity, except: [:join_excellent_course, :index, :create, :new, :apply_to_join_course, :search_course_list, :get_historical_course_students, :mine, :search_slim, :board_list] 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, + :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, @@ -127,8 +128,8 @@ class CoursesController < ApplicationController # POST /courses # POST /courses.json def create - ActiveRecord::Base.transaction do - begin + begin + ActiveRecord::Base.transaction do @course = Course.new(name: params[:name], class_period: params[:class_period], credit: params[:credit], end_date: params[:end_date], is_public: params[:is_public], school_id: @school.id, authentication: params[:authentication], professional_certification: params[:professional_certification]) @@ -166,16 +167,19 @@ 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] @course.create_course_modules(course_module_types) end - rescue => e - uid_logger_error(e.message) - tip_exception(e.message) - raise ActiveRecord::Rollback end + CreateSubjectCourseStudentJob.perform_later(@course.id) if @course.subject && @course.subject.subject_appointments.count > 0 + rescue => e + uid_logger_error(e.message) + tip_exception(e.message) + raise ActiveRecord::Rollback end end @@ -212,7 +216,7 @@ class CoursesController < ApplicationController @course.update_attributes!(course_params.merge(extra_params)) @course.update_course_modules(params[:course_module_types]) - + Rails.logger.info("###############course_update_end") normal_status(0, "成功") rescue => e uid_logger_error(e.message) @@ -257,11 +261,17 @@ class CoursesController < ApplicationController normal_status("更新成功") end + def delete_informs + inform = @course.informs.find_by(id: params[:inform_id]) + inform.destroy! + normal_status("删除成功") + end + 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 @@ -297,7 +307,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 @@ -417,7 +427,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) @@ -701,6 +711,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) @@ -712,12 +723,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? @@ -802,43 +813,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 # 获取历史课堂,即用户管理的所有课堂以及课堂下的分班(去除当前课堂) @@ -1478,8 +1483,10 @@ class CoursesController < ApplicationController shixun_titles = shixun_homeworks.pluck(:name) + ["总得分"] # 更新实训作业成绩 - shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework| - homework.update_homework_work_score + unless course.is_end + shixun_homeworks.includes(:homework_challenge_settings, :published_settings, :homework_commons_shixun).each do |homework| + homework.update_homework_work_score + end end shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user) diff --git a/app/controllers/ecs/base_controller.rb b/app/controllers/ecs/base_controller.rb index 2cded249a..1ad40d7b3 100644 --- a/app/controllers/ecs/base_controller.rb +++ b/app/controllers/ecs/base_controller.rb @@ -47,6 +47,10 @@ class Ecs::BaseController < ApplicationController page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file diff --git a/app/controllers/ecs/ec_graduation_requirements_controller.rb b/app/controllers/ecs/ec_graduation_requirements_controller.rb index 95dafdb3c..0647a7914 100644 --- a/app/controllers/ecs/ec_graduation_requirements_controller.rb +++ b/app/controllers/ecs/ec_graduation_requirements_controller.rb @@ -15,19 +15,31 @@ class Ecs::EcGraduationRequirementsController < Ecs::BaseController end def create - graduation_requirement = current_year.graduation_requirements.new + graduation_requirement = current_year.ec_graduation_requirements.new @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params) render 'show' end def update - graduation_requirement = current_year.graduation_requirements.find(params[:id]) - @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, update_params) + @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(current_graduation_requirement, update_params) render 'show' end + def destroy + ActiveRecord::Base.transaction do + current_graduation_requirement.destroy! + current_year.ec_graduation_requirements.where('position > ?', current_graduation_requirement.position) + .update_all('position = position - 1') + end + render_ok + end + private + def current_graduation_requirement + @_current_graduation_requirement ||= current_year.ec_graduation_requirements.find(params[:id]) + end + def create_params params.permit(:position, :content, graduation_subitems: [:content]) end diff --git a/app/controllers/ecs/ec_major_schools_controller.rb b/app/controllers/ecs/ec_major_schools_controller.rb index 058bc888e..c5f187af0 100644 --- a/app/controllers/ecs/ec_major_schools_controller.rb +++ b/app/controllers/ecs/ec_major_schools_controller.rb @@ -1,4 +1,6 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController + skip_before_action :check_user_permission!, only: [:show] + def index major_schools = current_school.ec_major_schools.not_template @@ -20,7 +22,18 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController @count = major_schools.count #检索后的数量,小于或等于全部数量 @major_schools = paginate(major_schools.includes(:users, :ec_major)) - @template_major_school = current_school.ec_major_schools.is_template.first #示例专业 + @template_major_school = EcMajorSchool.is_template.first #示例专业 + end + + # :show是 /api/ec_major_schools/:id + def show + @major = EcMajorSchool.find(params[:id]) + school = @major.school + + return if current_user.admin? || school.manager?(current_user) + return if @major.manager?(current_user) + + render_forbidden end def create diff --git a/app/controllers/ecs/ec_majors_controller.rb b/app/controllers/ecs/ec_majors_controller.rb index 7b14237dc..e8daaf008 100644 --- a/app/controllers/ecs/ec_majors_controller.rb +++ b/app/controllers/ecs/ec_majors_controller.rb @@ -1,7 +1,7 @@ class Ecs::EcMajorsController < Ecs::BaseController def index - school_major_subquery = current_school.ec_major_schools.select(:ec_major_id) #学校已选择的专业 - ec_majors = EcMajor.where.not(id: school_major_subquery) + @major_ids = current_school.ec_major_schools.pluck(:ec_major_id) #学校已选择的专业 + ec_majors = EcMajor.all if params[:search].present? ec_majors = ec_majors.search_name_or_code(params[:search]) diff --git a/app/controllers/ecs/ec_training_objectives_controller.rb b/app/controllers/ecs/ec_training_objectives_controller.rb index 318faa6ff..79b232822 100644 --- a/app/controllers/ecs/ec_training_objectives_controller.rb +++ b/app/controllers/ecs/ec_training_objectives_controller.rb @@ -2,7 +2,7 @@ class Ecs::EcTrainingObjectivesController < Ecs::BaseController before_action :check_major_manager_permission!, only: [:create] def show - @training_objective = current_year.ec_training_objective + @training_objective = current_year.ec_training_objective || current_year.build_ec_training_objective respond_to do |format| format.json diff --git a/app/controllers/ecs/ec_years_controller.rb b/app/controllers/ecs/ec_years_controller.rb index 2257911a7..9764e451d 100644 --- a/app/controllers/ecs/ec_years_controller.rb +++ b/app/controllers/ecs/ec_years_controller.rb @@ -10,7 +10,7 @@ class Ecs::EcYearsController < Ecs::BaseController end @count = ec_years.count - @ec_years = paginate ec_years + @ec_years = paginate ec_years.order(year: :desc) return if @ec_years.blank? @@ -27,13 +27,17 @@ class Ecs::EcYearsController < Ecs::BaseController .where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count end + def show + @year = current_year + end + def create if current_major_school.ec_years.exists?(year: params[:year].to_i) render_error('届别已存在') return end - @ec_year = CopyEcYearService.call(current_major_school, params[:year].to_i) + @ec_year = Ecs::CopyEcYearService.call(current_major_school, params[:year].to_i) end def destroy diff --git a/app/controllers/ecs/graduation_course_supports_controller.rb b/app/controllers/ecs/graduation_course_supports_controller.rb index 2a6d59024..c70121a0d 100644 --- a/app/controllers/ecs/graduation_course_supports_controller.rb +++ b/app/controllers/ecs/graduation_course_supports_controller.rb @@ -3,6 +3,7 @@ class Ecs::GraduationCourseSupportsController < Ecs::BaseController def show @graduation_subitems = current_year.ec_graduation_subitems + .reorder('ec_graduation_requirements.position ASC, ec_graduation_subitems.position ASC') .includes(:ec_graduation_requirement, ec_course_supports: :ec_course) @course_count = current_year.ec_courses.count diff --git a/app/controllers/ecs/graduation_subitems_controller.rb b/app/controllers/ecs/graduation_subitems_controller.rb new file mode 100644 index 000000000..03cf379bb --- /dev/null +++ b/app/controllers/ecs/graduation_subitems_controller.rb @@ -0,0 +1,6 @@ +class Ecs::GraduationSubitemsController < Ecs::BaseController + def index + subitems = current_year.ec_graduation_subitems.reorder('ec_graduation_requirements.position ASC, ec_graduation_subitems.position ASC') + @graduation_subitems = subitems.includes(:ec_graduation_requirement) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/major_managers_controller.rb b/app/controllers/ecs/major_managers_controller.rb index da5682734..d2515745b 100644 --- a/app/controllers/ecs/major_managers_controller.rb +++ b/app/controllers/ecs/major_managers_controller.rb @@ -3,7 +3,8 @@ class Ecs::MajorManagersController < Ecs::BaseController before_action :check_manager_permission! def create - @user = Ecs::CreateMajorManagerService.call(current_major_school, params[:user_id]) + Ecs::CreateMajorManagerService.call(current_major_school, params[:user_ids]) + render_ok rescue Ecs::CreateMajorManagerService::Error => ex render_error(ex.message) end diff --git a/app/controllers/ecs/reach_evaluations_controller.rb b/app/controllers/ecs/reach_evaluations_controller.rb index 97576447c..25ac24656 100644 --- a/app/controllers/ecs/reach_evaluations_controller.rb +++ b/app/controllers/ecs/reach_evaluations_controller.rb @@ -14,5 +14,13 @@ class Ecs::ReachEvaluationsController < Ecs::BaseController end def create + relations = current_year.ec_graduation_requirements.joins(ec_graduation_subitems: :ec_course_support) + ec_course_ids = relations.pluck('ec_course_supports.ec_course_id').uniq + + EcCourse.where(id: ec_course_ids).each do |ec_course| + Ecs::CalculateCourseEvaluationService.call(ec_course) + end + + render_ok end end diff --git a/app/controllers/ecs/students_controller.rb b/app/controllers/ecs/students_controller.rb index c21d625e0..abc5ddb65 100644 --- a/app/controllers/ecs/students_controller.rb +++ b/app/controllers/ecs/students_controller.rb @@ -14,7 +14,7 @@ class Ecs::StudentsController < Ecs::BaseController end def import - success_count = Ecs::ImportStudentService.call(current_year, params[:attachment_id]) + success_count = Ecs::ImportStudentService.call(current_year, params) render_ok(success_count: success_count) rescue Ecs::ImportStudentService::Error => ex render_error(ex.message) diff --git a/app/controllers/ecs/users_controller.rb b/app/controllers/ecs/users_controller.rb new file mode 100644 index 000000000..139893efc --- /dev/null +++ b/app/controllers/ecs/users_controller.rb @@ -0,0 +1,22 @@ +class Ecs::UsersController < Ecs::BaseController + skip_before_action :check_user_permission! + before_action :check_manager_permission! + + def index + users = UserQuery.call(params) + + @count = users.count + @users = paginate users.includes(user_extension: [:school, :department]) + @manager_ids = current_major_school.ec_major_school_users.pluck(:user_id) + end + + private + + def current_major_school + @_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id]) + end + + def current_school + @_current_school ||= current_major_school.school + end +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 89b6dca27..be8173b2f 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 : 中文排序问题 @@ -476,10 +476,13 @@ class GamesController < ApplicationController if @myshixun.shixun.try(:status) < 2 tip_exception("代码获取异常,请检查实训模板的评测设置是否正确") else - # 报错继续retry tip_exception(-3, "#{e.message}") end end + # 如果报错了,并且retry 为1的时候,则fork一个新的仓库 + if params[:retry].to_i == 1 + project_fork(@myshixun, @shixun.repo_path, current_user.login) + end tip_exception(0, e.message) end end @@ -530,18 +533,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 +558,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_ip_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 +876,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) @@ -916,9 +931,53 @@ class GamesController < ApplicationController # 更新关卡状态和一些学习进度 def update_game_parameter game game.update_attribute(:status, 0) if game.status == 1 - game.update_attributes(status: 0, open_time: Time.now) if game.status == 3 + # 第一次进入关卡更新时间 + game.update_attributes(status: 0, open_time: Time.now) if game.open_time.blank? || game.status == 3 # 开启实训更新myshixuns的时间,方便跟踪用于的学习进度。 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/gits_controller.rb b/app/controllers/gits_controller.rb index 910864812..b52e75353 100644 --- a/app/controllers/gits_controller.rb +++ b/app/controllers/gits_controller.rb @@ -19,43 +19,48 @@ class GitsController < ApplicationController result = false if request.env["HTTP_AUTHORIZATION"] && request.env["HTTP_AUTHORIZATION"].split(" ").length == 2 username_password = Base64.decode64(request.env["HTTP_AUTHORIZATION"].split(" ")[1]) - input_username = username_password.split(":")[0].strip() - input_password = username_password.split(":")[1].strip() - uid_logger("git start auth: input_username is #{input_username}") - - # Git 超级权限用户 - if input_username.strip == gituser.strip && input_password.strip == gitpassword.strip - result = true + if username_password.split(":")[0].nil? || username_password.split(":")[1].nil? + result = false else - # 用户是否对对象拥有权限 - system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username) + input_username = username_password.split(":")[0].strip() + input_password = username_password.split(":")[1].strip() + uid_logger("git start auth: input_username is #{input_username}") + - # 如果用户名密码错误 - if system_user && !system_user.check_password?(input_password) - uid_logger_error("git start: password is wrong") - result = false + # Git 超级权限用户 + if input_username.strip == gituser.strip && input_password.strip == gitpassword.strip + result = true else - git_url = params["url"] - username = git_url.split("/")[0] - shixunname = git_url.split("/")[1].split(".")[0] - repo_name = username + "/" + shixunname - uid_logger("git start: repo_name is #{repo_name}") - shixun = Shixun.select([:id, :user_id, :repo_name, :identifier]).where(repo_name: repo_name).first - uid_logger("git start auth: shixun identifier is #{shixun.try(:identifier)}") - uid_logger("git start auth: systemuser is #{system_user.try(:login)}") + # 用户是否对对象拥有权限 + system_user = User.find_by_login(input_username) || User.find_by_mail(input_username) || User.find_by_phone(input_username) - if shixun.present? - if system_user.present? && system_user.manager_of_shixun?(shixun) - result = true + # 如果用户名密码错误 + if system_user && !system_user.check_password?(input_password) + uid_logger_error("git start: password is wrong") + result = false + else + git_url = params["url"] + username = git_url.split("/")[0] + shixunname = git_url.split("/")[1].split(".")[0] + repo_name = username + "/" + shixunname + uid_logger("git start: repo_name is #{repo_name}") + shixun = Shixun.select([:id, :user_id, :repo_name, :identifier]).where(repo_name: repo_name).first + uid_logger("git start auth: shixun identifier is #{shixun.try(:identifier)}") + uid_logger("git start auth: systemuser is #{system_user.try(:login)}") + + if shixun.present? + if system_user.present? && system_user.manager_of_shixun?(shixun) + result = true + else + uid_logger_error("gituser is not shixun manager") + result = false + end else - uid_logger_error("gituser is not shixun manager") - result = false + uid_logger_error("shixun is not exist") + # result = false + result = true # 为了测试跳出 end - else - uid_logger_error("shixun is not exist") - # result = false - result = true # 为了测试跳出 end end end diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb index fe7511e29..de48f9fdb 100644 --- a/app/controllers/graduation_tasks_controller.rb +++ b/app/controllers/graduation_tasks_controller.rb @@ -168,7 +168,7 @@ class GraduationTasksController < ApplicationController end end else - @work_list = @work + @work_list = !@task.published? ? [] : @work @view_work = false @work_count = @work_list.count @all_work_count = @work_list.count @@ -324,9 +324,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}'") @@ -350,7 +350,7 @@ class GraduationTasksController < ApplicationController tip_exception(e.message) raise ActiveRecord::Rollback end - end + # end end def end_task @@ -401,7 +401,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] @@ -414,7 +414,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 @@ -426,7 +426,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 bd93401f3..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 @@ -230,6 +230,7 @@ class GraduationTopicsController < ApplicationController topic_repeat: topic.topic_repeat, province: topic.province, city: topic.city, + topic_type: topic.topic_type, course_list_id: @course.course_list_id) topic_bank.attachments.destroy_all else @@ -241,6 +242,7 @@ class GraduationTopicsController < ApplicationController topic_repeat: topic.topic_repeat, province: topic.province, city: topic.city, + topic_type: topic.topic_type, course_list_id: @course.course_list_id, user_id: current_user.id, graduation_topic_id: topic.id) 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 8268382bd..06ee8feee 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -82,8 +82,9 @@ class HomeworkCommonsController < ApplicationController end @task_count = @homework_commons.size - @homework_commons = @homework_commons.order("IF(ISNULL(homework_commons.publish_time),0,1), homework_commons.publish_time DESC, - homework_commons.created_at 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) @@ -112,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 @@ -926,17 +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 - 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,28 +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 - 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 @@ -1067,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| # 作业未发布时 @@ -1138,7 +1125,7 @@ class HomeworkCommonsController < ApplicationController tip_exception("发布失败") raise ActiveRecord::Rollback end - end + # end end def end_groups @@ -1167,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 # 分组设置 @@ -1184,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 @@ -1207,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/polls_controller.rb b/app/controllers/polls_controller.rb index 7cb7ee800..6ffe277a3 100644 --- a/app/controllers/polls_controller.rb +++ b/app/controllers/polls_controller.rb @@ -692,7 +692,7 @@ class PollsController < ApplicationController else unified_setting = @poll.unified_setting end - show_result = params[:show_result] ? 1 : 0 + show_result = params[:show_result].to_i un_anonymous = params[:un_anonymous] ? true : false # 统一设置或者分班为0,则更新问卷,并删除问卷分组 if unified_setting || (course_group_ids.size == 0) 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 8591f9821..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] @@ -8,11 +9,11 @@ class ShixunsController < ApplicationController before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns, :propaedeutics, :departments, :apply_shixun_mirror, - :get_mirror_script, :download_file] + :get_mirror_script, :download_file, :shixun_list] before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns, :propaedeutics, :departments, :apply_shixun_mirror, - :get_mirror_script, :download_file] + :get_mirror_script, :download_file, :shixun_list] before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy, :add_file] before_action :allowed, only: [:update, :close, :update_propaedeutics, :settings, :publish, @@ -98,6 +99,53 @@ class ShixunsController < ApplicationController .each_with_object({}) { |r, obj| obj[r.shixun_id] = r.name } end + def shixun_list + # 全部实训/我的实训 + type = params[:type] || "all" + # 状态:已发布/未发布 + status = params[:status] || "all" + + # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭) + if type == "mine" + @shixuns = current_user.shixuns.none_closed + else + if current_user.admin? + @shixuns = Shixun.none_closed.where(hidden: 0) + else + none_shixun_ids = ShixunSchool.where("school_id != #{current_user.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 + + page = params[:page] || 1 + 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 + ## 获取顶部菜单 def menus @repertoires = Repertoire.includes(sub_repertoires: [:tag_repertoires]).order("updated_at asc") @@ -181,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| @@ -409,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]}") @@ -424,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 @@ -601,7 +674,7 @@ class ShixunsController < ApplicationController challenges.each_with_index do |challenge, index| status = (index == 0 ? 0 : 3) game_identifier = generate_identifier(Game, 12) - worker.add(base_attr.merge(challenge_id: challenge.id, status: status, open_time: Time.now, + worker.add(base_attr.merge(challenge_id: challenge.id, status: status, identifier: game_identifier, modify_time: challenge.modify_time)) end end @@ -779,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 @@ -865,6 +962,7 @@ class ShixunsController < ApplicationController def send_to_course @course = Course.find(params[:course_id]) homework = HomeworksService.new.create_homework @shixun, @course, nil, current_user + CreateStudentWorkJob.perform_later(homework.id) end # 二维码扫描下载 @@ -891,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 @@ -914,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 @@ -949,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..2612510c5 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] @@ -318,11 +321,12 @@ class StudentWorksController < ApplicationController ActiveRecord::Base.transaction do begin - revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last - if revise_attachment.present? && @work.student_works_scores.where("created_at > '#{revise_attachment.created_on}' - and score is not null").count == 0 - revise_attachment.destroy - end + # 补交作业附件不覆盖之前上传的附件 + # revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last + # if revise_attachment.present? && @work.student_works_scores.where("created_at > '#{revise_attachment.created_on}' + # and score is not null").count == 0 + # revise_attachment.destroy + # end Attachment.associate_container(params[:attachment_ids], @work.id, @work.class, 7) revise_attachment = Attachment.where(attachtype: 7, container_id: @work.id, container_type: "StudentWork").last revise_attachment.update_attributes(description: params[:description]) if revise_attachment.present? @@ -455,6 +459,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 +473,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 d97b7172c..b7b208842 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -203,25 +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 - 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 @@ -369,7 +368,7 @@ class SubjectsController < ApplicationController @schools.map do |s| school_courses = Course.where(id: course_ids, school_id: s.id) course_count = school_courses.count - student_count = StudentsForCourse.where(course_id: school_courses.pluck(:id)).count + student_count = CourseMember.where(course_id: school_courses.pluck(:id), role: 4).count homework_count = HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id where c.school_id = #{s.id} and hc.id in(#{homework_common_id})").first.try(:cnt) s.attributes.dup.merge({name: s.name, course_count: course_count, student_count: student_count,homework_count: homework_count}) @@ -416,6 +415,20 @@ class SubjectsController < ApplicationController order by ue_count desc limit 10") end + # 预约报名 + def appointment + tip_exception("还存在未结束的课堂") unless @subject.max_course_end_date.nil? || @subject.max_course_end_date < Date.today + tip_exception("无需重复报名") if @subject.subject_appointments.exists?(user_id: current_user.id) + ActiveRecord::Base.transaction do + @subject.subject_appointments << SubjectAppointment.new(user_id: current_user.id) + @subject.increment!(:participant_count) + if @subject.participant_count == @subject.student_count + @subject.start_course_notify + end + normal_status("预约成功") + end + end + private def subject_params tip_exception("实训路径名称不能为空") if params[:name].blank? @@ -441,8 +454,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 @@ -451,15 +464,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/base_controller.rb b/app/controllers/users/base_controller.rb index 3ba6940f5..128dc539b 100644 --- a/app/controllers/users/base_controller.rb +++ b/app/controllers/users/base_controller.rb @@ -55,7 +55,13 @@ class Users::BaseController < ApplicationController page = page_value per_page = per_page_value - return Kaminari.paginate_array(objs).page(page).per(per_page) unless opts[:special] && observed_logged_user? + unless opts[:special] && observed_logged_user? + if objs.is_a?(Array) + return Kaminari.paginate_array(objs).page(page).per(per_page) + else + return objs.page(page).per(per_page) + end + end # note: 为实现第一页少一条记录,让前端放置新建入口 if page == 1 diff --git a/app/controllers/users/question_banks_controller.rb b/app/controllers/users/question_banks_controller.rb index d2f111973..c5b837d0b 100644 --- a/app/controllers/users/question_banks_controller.rb +++ b/app/controllers/users/question_banks_controller.rb @@ -1,10 +1,12 @@ class Users::QuestionBanksController < Users::BaseController before_action :require_login + 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 @@ -29,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) @@ -64,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 new file mode 100644 index 000000000..0b66cc263 --- /dev/null +++ b/app/controllers/wechats/js_sdk_signatures_controller.rb @@ -0,0 +1,11 @@ +class Wechats::JsSdkSignaturesController < ApplicationController + def create + timestamp = Time.now.to_i + noncestr = ('A'..'z').to_a.sample(8).join + signature = Util::Wechat.js_sdk_signature(params[:url], noncestr, timestamp) + + render_ok(appid: Util::Wechat.appid, timestamp: timestamp, noncestr: noncestr, signature: signature) + rescue Util::Wechat::Error => ex + render_error(ex.message) + end +end \ No newline at end of file diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 81093dc12..b4f851e5f 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -81,12 +81,12 @@ module TidingDecorator end def student_join_course_content - I18n.t(locale_format) % Course.find_by(id: container_id)&.name + I18n.t(locale_format) % [trigger_user.show_real_name, Course.find_by(id: container_id)&.name] end 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 @@ -384,4 +384,8 @@ module TidingDecorator def public_course_start_content I18n.t(locale_format) % [belong_container&.name, belong_container&.start_date&.strftime("%Y-%m-%d")] end + + def subject_start_course_content + I18n.t(locale_format) % belong_container&.name + end end 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..dbdcaea40 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? @@ -131,10 +126,11 @@ module ApplicationHelper # 用户图像url,如果不存在的话,source为匿名用户,即默认使用匿名用户图像 def url_to_avatar(source) if File.exist?(disk_filename(source.class, source.id)) + ctime = File.ctime(disk_filename(source.class, source.id)).to_i if source.class.to_s == 'User' - File.join(relative_path, ["#{source.class}", "#{source.id}"]) + File.join(relative_path, ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" else - File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + File.join("images/avatars", ["#{source.class}", "#{source.id}"]) + "?t=#{ctime}" end elsif source.class.to_s == 'User' str = source.user_extension.try(:gender).to_i == 0 ? "b" : "g" 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 c5d376baf..5ca4eb773 100644 --- a/app/helpers/courses_helper.rb +++ b/app/helpers/courses_helper.rb @@ -108,6 +108,10 @@ module CoursesHelper course_board.present? ? course_board.messages.size : 0 when "course_group" course.course_groups_count + when "announcement" + course.informs.count + when "online_learning" + course.shixuns.count end end @@ -265,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/ecs/ec_years_helper.rb b/app/helpers/ecs/ec_years_helper.rb new file mode 100644 index 000000000..108abb0e7 --- /dev/null +++ b/app/helpers/ecs/ec_years_helper.rb @@ -0,0 +1,22 @@ +module Ecs::EcYearsHelper + def achieved_graduation_course_count(ec_year) + return 0 if ec_year.ec_courses.count.zero? + + course_ids = ec_year.ec_courses.map(&:id) + target_count_map = EcCourseTarget.where(ec_course_id: course_ids).group(:ec_course_id).count + + ec_year.ec_courses.sum { |course| course.complete_target_count == target_count_map[course.id] ? 1 : 0 } + end + + def achieved_graduation_objective_count(ec_year) + return 0 if ec_year.ec_graduation_subitems.count.zero? + + subitem_ids = ec_year.ec_graduation_subitems.reorder(nil).pluck(:id) + + relations = EcGraduationRequirementCalculation.joins(:ec_course_support).where(ec_course_supports: { ec_graduation_subitem_id: subitem_ids }) + + reached_map = relations.where(status: true).group('ec_graduation_subitem_id').count + + reached_map.keys.size + end +end \ No newline at end of file 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/jobs/apply_teacher_role_join_course_notify_job.rb b/app/jobs/apply_teacher_role_join_course_notify_job.rb index 3ae5e32db..ab5a9e354 100644 --- a/app/jobs/apply_teacher_role_join_course_notify_job.rb +++ b/app/jobs/apply_teacher_role_join_course_notify_job.rb @@ -8,7 +8,7 @@ class ApplyTeacherRoleJoinCourseNotifyJob < ApplicationJob return if user.blank? || course.blank? attrs = %i[user_id trigger_user_id container_id container_type belong_container_id - belong_container_type tiding_type extra created_at updated_at] + belong_container_type tiding_type status extra created_at updated_at] same_attrs = { trigger_user_id: user.id, container_id: course.id, container_type: 'JoinCourse', status: 0, diff --git a/app/jobs/create_subject_course_student_job.rb b/app/jobs/create_subject_course_student_job.rb new file mode 100644 index 000000000..a7b8cb8af --- /dev/null +++ b/app/jobs/create_subject_course_student_job.rb @@ -0,0 +1,22 @@ +class CreateSubjectCourseStudentJob < ApplicationJob + queue_as :default + + def perform(course_id) + course = Course.find_by(id: course_id) + return if course.blank? || course.subject.blank? + + attrs = %i[course_id user_id role created_at updated_at] + same_attrs = {course_id: course.id, role: 4} + + Rails.logger.info("1:course.students.count:##{course.students.count}") + CourseMember.bulk_insert(*attrs) do |worker| + course.subject.subject_appointments.each do |app| + Rails.logger.info("##{course.students.where(user_id: app.user_id)}") + next if course.students.where(user_id: app.user_id).any? + worker.add same_attrs.merge(user_id: app.user_id) + end + end + Rails.logger.info("2:course.students.count:##{course.students.count}") + course.subject.subject_appointments.destroy_all + end +end diff --git a/app/libs/util.rb b/app/libs/util.rb index f39ce2b58..ae2e4b80b 100644 --- a/app/libs/util.rb +++ b/app/libs/util.rb @@ -45,6 +45,8 @@ module Util def conceal(str, type = nil) str = str.to_s + return if str.blank? + case type when :phone then "#{str[0..2]}***#{str[-4..-1]}" when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}" diff --git a/app/libs/util/file_manage.rb b/app/libs/util/file_manage.rb index 620fd7f01..b6cd79e57 100644 --- a/app/libs/util/file_manage.rb +++ b/app/libs/util/file_manage.rb @@ -10,10 +10,26 @@ 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 exists?(source) + File.exist?(disk_filename(source.class, source.id)) + end + + def disk_file_url(source_type, source_id) + File.join('/images', relative_path, "#{source_type}", "#{source_id}") + end + + def source_disk_file_url(source) + File.join('/images', relative_path, "#{source.class}", "#{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/redis.rb b/app/libs/util/redis.rb new file mode 100644 index 000000000..f240406f5 --- /dev/null +++ b/app/libs/util/redis.rb @@ -0,0 +1,9 @@ +module Util::Redis + class << self + def online_user_count + if Rails.cache.is_a?(ActiveSupport::Cache::RedisStore) + Rails.cache.data.scan(0, match: 'cache:_session_id:*', count: 100000).last.uniq.size + end + end + end +end \ No newline at end of file diff --git a/app/libs/util/wechat.rb b/app/libs/util/wechat.rb new file mode 100644 index 000000000..1b064ba94 --- /dev/null +++ b/app/libs/util/wechat.rb @@ -0,0 +1,75 @@ +module Util::Wechat + BASE_SITE = 'https://api.weixin.qq.com'.freeze + + Error = Class.new(StandardError) + + class << self + attr_accessor :appid, :secret + + def js_sdk_signature(url, noncestr, timestamp) + data = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url } + str = data.map { |k, v| "#{k}=#{v}" }.join('&') + Digest::SHA1.hexdigest(str) + end + + def access_token + # 7200s 有效时间 + Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential') + result['access_token'] + end + end + + def refresh_access_token + Rails.cache.delete(access_token_cache_key) + access_token + end + + def jsapi_ticket + # 7200s 有效时间 + Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi') + result['ticket'] + end + end + + def refresh_jsapi_ticket + Rails.cache.delete(jsapi_ticket_cache_key) + jsapi_ticket + end + + def access_token_cache_key + "#{base_cache_key}/access_token" + end + + def jsapi_ticket_cache_key + "#{base_cache_key}/jsapi_ticket" + end + + def base_cache_key + "wechat/#{appid}" + end + + private + + def request(method, url, **params) + Rails.logger.error("[wechat] request: #{method} #{url} #{params.inspect}") + + client = Faraday.new(url: BASE_SITE) + response = client.public_send(method, url, params) + result = JSON.parse(response.body) + + Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}") + + if response.status != 200 + raise Error, result.inspect + end + + if result['errcode'].present? && result['errcode'].to_i.nonzero? + raise Error, result.inspect + end + + result + end + end +end \ No newline at end of file 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/apply_user_authentication.rb b/app/models/apply_user_authentication.rb index c379fb82e..4f94202f6 100644 --- a/app/models/apply_user_authentication.rb +++ b/app/models/apply_user_authentication.rb @@ -18,6 +18,10 @@ class ApplyUserAuthentication < ApplicationRecord nil end + def revoke! + update!(status: 3) + end + private def send_tiding 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..a3578d500 100644 --- a/app/models/course_message.rb +++ b/app/models/course_message.rb @@ -28,10 +28,10 @@ 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 ) # 将申请消息置为已处理 - Tiding.where(trigger_user_id: user_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1) + Tiding.where(trigger_user_id: course_message_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1) end end \ No newline at end of file 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/department.rb b/app/models/department.rb index 3b0672cce..2c537fd91 100644 --- a/app/models/department.rb +++ b/app/models/department.rb @@ -5,7 +5,7 @@ class Department < ApplicationRecord has_many :member_users, through: :department_members, source: :user has_many :user_extensions, dependent: :nullify - has_many :apply_add_departments + has_many :apply_add_departments, dependent: :destroy scope :without_deleted, -> { where(is_delete: false) } diff --git a/app/models/ec_course_student_score.rb b/app/models/ec_course_student_score.rb index 5b45e34a9..57d524b46 100644 --- a/app/models/ec_course_student_score.rb +++ b/app/models/ec_course_student_score.rb @@ -1,7 +1,6 @@ class EcCourseStudentScore < ApplicationRecord belongs_to :ec_year_student belongs_to :ec_course - belongs_to :ec_course_target has_many :ec_student_score_targets, dependent: :delete_all end \ No newline at end of file diff --git a/app/models/ec_course_support.rb b/app/models/ec_course_support.rb index a6ca96ea9..518fc1385 100644 --- a/app/models/ec_course_support.rb +++ b/app/models/ec_course_support.rb @@ -1,9 +1,10 @@ class EcCourseSupport < ApplicationRecord default_scope { order(position: :asc) } + alias_attribute :weights, :weigths + belongs_to :ec_course belongs_to :ec_graduation_subitem - # TODO: 将 ec_graduation_subitem_courses 移除,这个表作为关系表 has_one :ec_graduation_requirement_calculation, dependent: :destroy diff --git a/app/models/ec_course_target.rb b/app/models/ec_course_target.rb index 9b93cb73c..b13c81059 100644 --- a/app/models/ec_course_target.rb +++ b/app/models/ec_course_target.rb @@ -1,4 +1,3 @@ -# TODO:: change table column :weigths => :weight class EcCourseTarget < ApplicationRecord belongs_to :ec_course @@ -8,6 +7,8 @@ class EcCourseTarget < ApplicationRecord has_many :ec_course_achievement_methods, dependent: :destroy has_many :ec_achievement_evaluation_relates, dependent: :destroy + alias_attribute :weight, :weigths + validates :content, presence: true validates :standard_grade, numericality: { only_integer: true, greater_than: 0 } validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 } 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_graduation_requirement.rb b/app/models/ec_graduation_requirement.rb index d0f4195d0..f9c65e28e 100644 --- a/app/models/ec_graduation_requirement.rb +++ b/app/models/ec_graduation_requirement.rb @@ -1,4 +1,6 @@ class EcGraduationRequirement < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_year has_many :ec_graduation_subitems, dependent: :destroy @@ -7,5 +9,5 @@ class EcGraduationRequirement < ApplicationRecord validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } validates :content, presence: true - default_scope { order(position: :asc) } + accepts_nested_attributes_for :ec_graduation_subitems, allow_destroy: true 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_major_school.rb b/app/models/ec_major_school.rb index 41a835f63..5cfc4df9e 100644 --- a/app/models/ec_major_school.rb +++ b/app/models/ec_major_school.rb @@ -12,6 +12,8 @@ class EcMajorSchool < ApplicationRecord scope :is_template, -> { where(template_major: true) } scope :not_template, -> { where(template_major: false) } + delegate :code, :name, to: :ec_major + # 是否为该专业管理员 def manager?(user) ec_major_school_users.exists?(user_id: user.id) 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/ec_training_subitem.rb b/app/models/ec_training_subitem.rb index 0c9c61fbc..736e3f0da 100644 --- a/app/models/ec_training_subitem.rb +++ b/app/models/ec_training_subitem.rb @@ -1,4 +1,6 @@ class EcTrainingSubitem < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_training_objective has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy diff --git a/app/models/ec_year.rb b/app/models/ec_year.rb index 69ae4c291..6a3d97340 100644 --- a/app/models/ec_year.rb +++ b/app/models/ec_year.rb @@ -9,4 +9,11 @@ class EcYear < ApplicationRecord has_many :ec_graduation_requirements, dependent: :destroy has_many :ec_graduation_subitems, through: :ec_graduation_requirements has_many :ec_year_students, dependent: :destroy + + has_many :ec_course_users, dependent: :destroy + has_many :managers, through: :ec_course_users, source: :user + + def prev_year + self.class.find_by(year: year.to_i - 1) + end 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 e247f2b6e..17309101d 100644 --- a/app/models/graduation_task.rb +++ b/app/models/graduation_task.rb @@ -37,7 +37,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/graduation_work.rb b/app/models/graduation_work.rb index 235bfcac6..c7420ffef 100644 --- a/app/models/graduation_work.rb +++ b/app/models/graduation_work.rb @@ -48,7 +48,7 @@ class GraduationWork < ApplicationRecord def delete_atta atta last_score = graduation_work_scores.where.not(score: nil).last - atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + (atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on) end # 分班名 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..40de5a87c 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 # 是否在补交阶段内 @@ -134,6 +134,11 @@ class HomeworkCommon < ApplicationRecord self.homework_type == 'practice' && self.publish_time.present? && self.publish_time < Time.now && self.homework_group_reviews.count == 0 end + # 作业查看最新成绩 + def update_score identity + identity < Course::NORMAL && publish_time.present? && publish_time < Time.now && !course.is_end + end + # 作业能否立即发布 def publish_immediately user homework_detail_manual.try(:comment_status) == 0 || homework_group_settings.where(course_group_id: course.charge_group_ids(user)). diff --git a/app/models/poll.rb b/app/models/poll.rb index 7f0d2fd94..9cb860f61 100644 --- a/app/models/poll.rb +++ b/app/models/poll.rb @@ -104,7 +104,7 @@ class Poll < ApplicationRecord status = 4 else if user.present? && user.student_of_course?(course) - ex_time = get_poll_times(user_id,false) + ex_time = get_poll_times(user.id,false) pb_time = ex_time[:publish_time] ed_time = ex_time[:end_time] if pb_time.present? && ed_time.present? && pb_time <= Time.now && ed_time > Time.now diff --git a/app/models/school.rb b/app/models/school.rb index 1034fd997..387b6b5d8 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -16,6 +16,9 @@ class School < ApplicationRecord has_many :customers, dependent: :destroy has_many :partners, dependent: :destroy + has_many :apply_add_departments, dependent: :destroy + has_many :user_extensions, dependent: :nullify + # 学校管理员 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 db6bca43e..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 @@ -59,6 +65,7 @@ class Shixun < ApplicationRecord scope :visible, -> { where.not(status: -1) } scope :published, lambda{ where(status: 2) } scope :published_closed, lambda{ where(status: [2, 3]) } + scope :none_closed, lambda{ where(status: [0, 1, 2]) } scope :unhidden, lambda{ where(hidden: 0, status: 2) } scope :field_for_recommend, lambda{ select([:id, :name, :identifier, :myshixuns_count]) } scope :find_by_ids,lambda{|k| where(id:k)} @@ -273,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_graduation_topic.rb b/app/models/student_graduation_topic.rb index 50f150f92..b8f4dfbbb 100644 --- a/app/models/student_graduation_topic.rb +++ b/app/models/student_graduation_topic.rb @@ -21,7 +21,7 @@ class StudentGraduationTopic < ApplicationRecord def send_tiding self.tidings << Tiding.new(:user_id => self.graduation_topic.tea_id, :trigger_user_id => self.user_id, :parent_container_id => self.graduation_topic_id, :parent_container_type => "GraduationTopic", - :belong_container_id => self.graduation_topic.course_id, :belong_container_type => "Course", :viewed => 0, :status => 0, :tiding_type => "GraduationTopic") + :belong_container_id => self.graduation_topic.course_id, :belong_container_type => "Course", :viewed => 0, :status => 0, :tiding_type => "Apply") end # 学生名称 diff --git a/app/models/student_work.rb b/app/models/student_work.rb index 168cfeb68..b4ad834de 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(补交的附件) @@ -105,7 +106,7 @@ class StudentWork < ApplicationRecord def delete_atta atta last_score = student_works_scores.where.not(score: nil).last - atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + (atta.author_id == User.current.id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on) end # 作品总体评价 diff --git a/app/models/student_works_score.rb b/app/models/student_works_score.rb index 19043f7f8..299b61596 100644 --- a/app/models/student_works_score.rb +++ b/app/models/student_works_score.rb @@ -1,6 +1,6 @@ class StudentWorksScore < ApplicationRecord #appeal_status: 0:正常;1:申诉中,2:撤销申诉;3:申诉成功;4:申诉被拒绝;5:申诉失效 -belongs_to :student_work + belongs_to :student_work belongs_to :user has_many :journals_for_messages, -> { order('created_on desc') }, as: :jour, dependent: :destroy has_one :student_works_scores_appeal, dependent: :destroy @@ -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..d29a97d0c 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -13,6 +13,8 @@ class Subject < ApplicationRecord has_many :stage_shixuns, dependent: :destroy has_many :shixuns, through: :stage_shixuns + has_many :subject_appointments, dependent: :destroy + has_many :subject_members, ->{ order("subject_members.position asc")}, dependent: :destroy has_many :users, through: :subject_members has_many :tidings, as: :container, dependent: :destroy @@ -44,10 +46,13 @@ class Subject < ApplicationRecord courses.where("start_date <= '#{Date.today}' and end_date >= '#{Date.today}'").count > 0 end + def has_participate? + subject_appointments.exists?(user_id: User.current.id) + end + # 挑战过路径的成员数(金课统计去重后的报名人数) 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 @@ -110,4 +115,10 @@ class Subject < ApplicationRecord def learning? user_id Myshixun.where(user_id: user_id, shixun_id: shixuns).exists? end + + def start_course_notify + Tiding.create(user_id: user_id, trigger_user_id: 0, container_id: id, + container_type: 'SubjectStartCourse', belong_container_id: id, + belong_container_type: 'Subject', tiding_type: 'System') + end end \ No newline at end of file diff --git a/app/models/subject_appointment.rb b/app/models/subject_appointment.rb new file mode 100644 index 000000000..a4bc53b18 --- /dev/null +++ b/app/models/subject_appointment.rb @@ -0,0 +1,4 @@ +class SubjectAppointment < ApplicationRecord + belongs_to :subject + belongs_to :user +end 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.rb b/app/models/user.rb index 43c5728b5..b9d9e48e6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -26,8 +26,6 @@ class User < ApplicationRecord MIX_PASSWORD_LIMIT = 8 - LOGIN_CHARS = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z).freeze - has_one :user_extension, dependent: :destroy accepts_nested_attributes_for :user_extension, update_only: true @@ -348,7 +346,7 @@ class User < ApplicationRecord elsif business? Course::BUSINESS else - role = course.course_members.find_by(user_id: id, is_active: 1)&.role + role = course&.course_members&.find_by(user_id: id, is_active: 1)&.role case role when nil then Course::NORMAL when 'CREATOR' then Course::CREATOR diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 5a0dc8a37..0a2249308 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, enterprise: 4, unselect: -1 } belongs_to :user, touch: true belongs_to :school, optional: true diff --git a/app/queries/admins/department_apply_query.rb b/app/queries/admins/department_apply_query.rb new file mode 100644 index 000000000..500536ddb --- /dev/null +++ b/app/queries/admins/department_apply_query.rb @@ -0,0 +1,25 @@ +class Admins::DepartmentApplyQuery < 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 + status = params[:status] + + applies = ApplyAddDepartment.where(status: status) if status.present? + + # 关键字模糊查询 + keyword = params[:keyword].to_s.strip + if keyword.present? + applies = applies.where('name LIKE :keyword', keyword: "%#{keyword}%") + end + + custom_sort(applies, params[:sort_by], params[:sort_direction]) + end +end \ No newline at end of file diff --git a/app/queries/admins/school_query.rb b/app/queries/admins/school_query.rb new file mode 100644 index 000000000..7361588c4 --- /dev/null +++ b/app/queries/admins/school_query.rb @@ -0,0 +1,23 @@ +class Admins::SchoolQuery < ApplicationQuery + include CustomSortable + + attr_reader :params + + sort_columns :users_count, :created_at, default_by: :created_at, default_direction: :desc + + def initialize(params) + @params = params + end + + def call + schools = School.all + + keyword = strip_param(:keyword) + schools = schools.where('schools.name LIKE ?', "%#{keyword}%") if keyword + + schools = schools.joins(:user_extensions).group(:id) + schools = schools.select('schools.*, COUNT(*) AS users_count') + + custom_sort schools, params[:sort_by], params[:sort_direction] + end +end \ No newline at end of file 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/queries/application_query.rb b/app/queries/application_query.rb index 3a92cc6e8..c66af94c0 100644 --- a/app/queries/application_query.rb +++ b/app/queries/application_query.rb @@ -1,3 +1,9 @@ class ApplicationQuery include Callable + + private + + def strip_param(key) + params[key].to_s.strip.presence + end end \ No newline at end of file diff --git a/app/queries/user_query.rb b/app/queries/user_query.rb new file mode 100644 index 000000000..326665fe9 --- /dev/null +++ b/app/queries/user_query.rb @@ -0,0 +1,28 @@ +class UserQuery < ApplicationQuery + attr_reader :params + + def initialize(params) + @params = params + end + + def call + users = User.where(type: 'User') + + # 真实姓名 + if name = strip_param(:name) + users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%") + end + + # 单位名称 + if school = strip_param(:school) + users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school}%") + end + + # 职业 + if (identity = strip_param(:identity)) && UserExtension.identities.keys.include?(identity) + users = users.joins(:user_extension).where(user_extensions: { identity: identity }) + end + + users + end +end \ No newline at end of file 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/identity_auths/revoke_apply_service.rb b/app/services/admins/identity_auths/revoke_apply_service.rb new file mode 100644 index 000000000..e76d497a5 --- /dev/null +++ b/app/services/admins/identity_auths/revoke_apply_service.rb @@ -0,0 +1,26 @@ +class Admins::IdentityAuths::RevokeApplyService < ApplicationService + attr_reader :apply, :user + + def initialize(apply) + @apply = apply + @user = apply.user + end + + def call + ActiveRecord::Base.transaction do + apply.revoke! + user.update!(authentication: false) + + deal_tiding! + end + end + + private + + def deal_tiding! + Tiding.create!(user_id: apply.user_id, trigger_user_id: 0, + container_id: apply.id, container_type: 'CancelUserAuthentication', + belong_container_id: apply.user_id, belong_container_type: 'User', + status: 1, tiding_type: 'System') + end +end \ No newline at end of file diff --git a/app/services/admins/import_user_service.rb b/app/services/admins/import_user_service.rb index e5e7abfe6..f3408051b 100644 --- a/app/services/admins/import_user_service.rb +++ b/app/services/admins/import_user_service.rb @@ -46,6 +46,7 @@ class Admins::ImportUserService < ApplicationService department = school.departments.find_by(name: data.department_name) attr = { + type: 'User', status: User::STATUS_ACTIVE, login: "#{prefix}#{data.student_id}", firstname: '', @@ -54,7 +55,9 @@ class Admins::ImportUserService < ApplicationService professional_certification: 1, certification: 1, password: '12345678', - phone: data.phone + phone: data.phone, + mail: "#{prefix}#{data.student_id}@qq.com", + profile_completed: true } ActiveRecord::Base.transaction do user = User.create!(attr) @@ -66,8 +69,8 @@ class Admins::ImportUserService < ApplicationService extension_attr[:technical_title] = case data.identity.to_i - when 0 then %w(教授 副教授 讲师 助教).include?(data.technical_title) || '讲师' - when 2 then %w(企业管理者 部门管理者 高级工程师 工程师 助理工程师).include?(data.technical_title) || '助理工程师' + when 0 then %w(教授 副教授 讲师 助教).include?(data.technical_title) ? data.technical_title : '讲师' + when 2 then %w(企业管理者 部门管理者 高级工程师 工程师 助理工程师).include?(data.technical_title) ? data.technical_title : '助理工程师' else nil end diff --git a/app/services/admins/professional_auths/revoke_apply_service.rb b/app/services/admins/professional_auths/revoke_apply_service.rb new file mode 100644 index 000000000..1430e7ec8 --- /dev/null +++ b/app/services/admins/professional_auths/revoke_apply_service.rb @@ -0,0 +1,26 @@ +class Admins::ProfessionalAuths::RevokeApplyService < ApplicationService + attr_reader :apply, :user + + def initialize(apply) + @apply = apply + @user = apply.user + end + + def call + ActiveRecord::Base.transaction do + apply.revoke! + user.update!(professional_certification: false) + + deal_tiding! + end + end + + private + + def deal_tiding! + Tiding.create!(user_id: apply.user_id, trigger_user_id: 0, + container_id: apply.id, container_type: 'CancelUserProCertification', + belong_container_id: apply.user_id, belong_container_type: 'User', + status: 1, tiding_type: 'System') + 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/ecs/copy_ec_year_service.rb b/app/services/ecs/copy_ec_year_service.rb index 87cbe0845..462681eba 100644 --- a/app/services/ecs/copy_ec_year_service.rb +++ b/app/services/ecs/copy_ec_year_service.rb @@ -1,4 +1,4 @@ -class CopyEcYearService < ApplicationService +class Ecs::CopyEcYearService < ApplicationService attr_reader :major_school, :to_year def initialize(major_school, year) diff --git a/app/services/ecs/create_course_service.rb b/app/services/ecs/create_course_service.rb index dba162189..3e3828c6f 100644 --- a/app/services/ecs/create_course_service.rb +++ b/app/services/ecs/create_course_service.rb @@ -27,7 +27,7 @@ class Ecs::CreateCourseService < ApplicationService private def create_default_score_levels!(ec_course) - EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position) do |worker| + EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position, :created_at, :updated_at) do |worker| [ { ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 }, { ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 }, diff --git a/app/services/ecs/create_major_manager_service.rb b/app/services/ecs/create_major_manager_service.rb index befe80706..c955bffed 100644 --- a/app/services/ecs/create_major_manager_service.rb +++ b/app/services/ecs/create_major_manager_service.rb @@ -3,29 +3,30 @@ class Ecs::CreateMajorManagerService < ApplicationService MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制 - attr_reader :major_school, :user_id + attr_reader :major_school, :user_ids - def initialize(major_school, user_id) + def initialize(major_school, user_ids) @major_school = major_school - @user_id = user_id + @user_ids = user_ids end def call raise Error, '示例专业不能添加管理员' if major_school.template_major? - user = User.find_by(id: params[:user_id]) - raise Error, '该用户不存在' if user.blank? + @user_ids = User.where(id: user_ids).pluck(:id) - if major_school.ec_major_school_users.exists?(user_id: user.id) - raise Error, '该用户已经是该专业的管理员了' + if major_school.ec_major_school_users.exists?(user_id: user_ids) + raise Error, '所选用户中存在该专业的管理员' end - if major_school.ec_major_school_users.count >= MAJOR_MANAGER_COUNT_LIMIT - raise Error, '该专业管理员数量已达上限' + if major_school.ec_major_school_users.count + user_ids.count > MAJOR_MANAGER_COUNT_LIMIT + raise Error, "该专业管理员数量超过上限(#{MAJOR_MANAGER_COUNT_LIMIT}人)" end - major_school.ec_major_school_users.create!(user: user) - - user + ActiveRecord::Base.transaction do + user_ids.each do |user_id| + major_school.ec_major_school_users.create!(user_id: user_id) + end + end end end \ No newline at end of file diff --git a/app/services/ecs/create_training_objective_service.rb b/app/services/ecs/create_training_objective_service.rb index c3dc3c8a6..effbf5420 100644 --- a/app/services/ecs/create_training_objective_service.rb +++ b/app/services/ecs/create_training_objective_service.rb @@ -11,13 +11,16 @@ class Ecs::CreateTrainingObjectiveService < ApplicationService def call training_objective.content = params[:content].to_s.strip - attributes = build_accepts_nested_attributes( - training_objective, - training_objective.ec_training_subitems, - params[:training_subitems], - &method(:training_subitem_param_handler) - ) - training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + if params.key?(:training_subitems) + attributes = build_accepts_nested_attributes( + training_objective, + training_objective.ec_training_subitems, + params[:training_subitems], + &method(:training_subitem_param_handler) + ) + attributes.each_with_index { |attr, index| attr[:position] = index + 1 } + training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + end training_objective.save! training_objective diff --git a/app/services/ecs/import_student_service.rb b/app/services/ecs/import_student_service.rb index 9014e221c..f5cd7c6ac 100644 --- a/app/services/ecs/import_student_service.rb +++ b/app/services/ecs/import_student_service.rb @@ -1,21 +1,20 @@ class Ecs::ImportStudentService < ApplicationService Error = Class.new(StandardError) - attr_reader :ec_year, :attachment + attr_reader :ec_year, :params - def initialize(ec_year, attachment_id) - @ec_year = ec_year - @attachment = Attachment.find_by(id: attachment_id) + def initialize(ec_year, params) + @ec_year = ec_year + @params = params end def call - raise Error, '文件不存在' if attachment.blank? + raise Error, '文件不存在' if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) - path = attachment.diskfile - excel = Ecs::ImportStudentExcel.new(path) + excel = Ecs::ImportStudentExcel.new(params[:file].path) success_count = 0 - EcYearStudent.bulk_insert(:student_id, :name, :created_at, :updated_at) do |worker| + EcYearStudent.bulk_insert(:ec_year_id, :student_id, :name, :created_at, :updated_at) do |worker| excel.read_each do |student_id, name| success_count += 1 @@ -25,7 +24,7 @@ class Ecs::ImportStudentService < ApplicationService next end - worker.add(student_id: student_id, name: name) + worker.add(ec_year_id: ec_year.id, student_id: student_id, name: name) end end diff --git a/app/services/ecs/query_course_evaluation_service.rb b/app/services/ecs/query_course_evaluation_service.rb index 8c76da438..22e0ce1f4 100644 --- a/app/services/ecs/query_course_evaluation_service.rb +++ b/app/services/ecs/query_course_evaluation_service.rb @@ -17,12 +17,12 @@ class Ecs::QueryCourseEvaluationService < ApplicationService end def graduation_subitem_evaluations - student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) + student_scores = ec_course.ec_course_student_scores.joins(ec_student_score_targets: :ec_course_target).group(:ec_course_target_id) student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') student_score_map = student_scores.group_by { |item| item.ec_course_target_id } subitem_targets = ec_course.ec_graduation_subitem_course_targets - .includes(ec_graduation_subitem: :ec_graduation_requirement) + .includes(:ec_course_target, ec_graduation_subitem: :ec_graduation_requirement) subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr| subitem = arr.first.ec_graduation_subitem @@ -37,7 +37,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService arr.map(&:ec_course_target).uniq.each do |target| target_total_rates += target.weight.to_f - student_score = student_score_map[target.id] + student_score = student_score_map[target.id]&.first reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score end @@ -60,8 +60,19 @@ class Ecs::QueryCourseEvaluationService < ApplicationService def score_levels_map @_score_levels_map ||= begin + index = 0 ec_course.ec_score_levels.each_with_object({}) do |level, obj| - obj[level.id.to_s] = level.as_json(only: %i[id position score level]) + hash = level.as_json(only: %i[id position score level]) + + hash[:description] = + case index + when 0 then "#{level.score}分以上" + when ec_course.ec_score_levels.to_a.size - 1 then "低于#{level.score}分" + else "#{level.score}~#{ec_course.ec_score_levels[index - 1].score - 1}分" + end + + index += 1 + obj[level.id.to_s] = hash end end end @@ -87,23 +98,29 @@ class Ecs::QueryCourseEvaluationService < ApplicationService @_course_achievement += data[:average_score].to_f * course_target.weight.to_f # 计算学生成绩分布区间 + student_count = 0 data[:score_levels] = score_levels.map do |score_level| level_condition_proc = if (score_level.position - 1).zero? # 第一区间 -> (score_target){ score_target.score >= score_level.score ? 1 : 0 } - elsif score_levels.position == score_levels.size # 末尾区间 + elsif score_level.position == score_levels.size # 末尾区间 -> (score_target){ score_target.score < score_level.score ? 1 : 0 } else # 中间区间 - -> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 } + -> (score_target){ score_target.score >= score_level.score && score_target.score < score_levels[score_level.position - 1].score ? 1 : 0 } end # 计算该成绩区间人数 count = score_targets.sum(&level_condition_proc) + student_count += count { id: score_level.id, count: count } end + data[:score_levels].each do |score_level| + score_level[:rate] = score_level[:count].fdiv(student_count).round(2) + end + data end end diff --git a/app/services/ecs/save_graduation_course_supports_service.rb b/app/services/ecs/save_graduation_course_supports_service.rb index bfbdb997f..de4ecc71a 100644 --- a/app/services/ecs/save_graduation_course_supports_service.rb +++ b/app/services/ecs/save_graduation_course_supports_service.rb @@ -9,6 +9,8 @@ class Ecs::SaveGraduationCourseSupportsService < ApplicationService end def call + set_course_supports_position! + Ecs::SaveGraduationCourseSupportForm.new(params).validate! accepts_attributes = build_accepts_nested_attributes( @@ -20,4 +22,10 @@ class Ecs::SaveGraduationCourseSupportsService < ApplicationService graduation_subitem.save! graduation_subitem end + + def set_course_supports_position! + params[:course_supports].each_with_index do |item, index| + item[:position] = index + 1 + end + end end \ No newline at end of file diff --git a/app/services/homeworks_service.rb b/app/services/homeworks_service.rb index f6868afba..0dc814c89 100644 --- a/app/services/homeworks_service.rb +++ b/app/services/homeworks_service.rb @@ -15,7 +15,6 @@ class HomeworksService homework_detail_manual.save! if homework_detail_manual HomeworkCommonsShixun.create!(homework_common_id: homework.id, shixun_id: shixun.id) HomeworksService.new.create_shixun_homework_cha_setting(homework, shixun) - CreateStudentWorkJob.perform_later(homework.id) # HomeworksService.new.create_works_list(homework, course) end homework 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..74ee08c85 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/tasks/statistic_school_daily_report_task.rb b/app/tasks/statistic_school_daily_report_task.rb index 5cd3fda7c..794a4b573 100644 --- a/app/tasks/statistic_school_daily_report_task.rb +++ b/app/tasks/statistic_school_daily_report_task.rb @@ -27,8 +27,8 @@ class StatisticSchoolDailyReportTask # 新增实训评测数量 shixun_evaluate_count = EvaluateRecord.joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = evaluate_records.shixun_id') .joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4') - .joins('LEFT JOIN members ON members.user_id = evaluate_records.user_id') - .joins('LEFT JOIN courses ON members.course_id = courses.id AND hc.course_id = courses.id') + .joins('LEFT JOIN course_members ON course_members.user_id = evaluate_records.user_id') + .joins('LEFT JOIN courses ON course_members.course_id = courses.id AND hc.course_id = courses.id') .where(courses: { school_id: school.id }) .where(created_at: yesterday).reorder(nil).count diff --git a/app/tasks/statistic_school_report_task.rb b/app/tasks/statistic_school_report_task.rb index a55eb7a42..a72c57830 100644 --- a/app/tasks/statistic_school_report_task.rb +++ b/app/tasks/statistic_school_report_task.rb @@ -2,10 +2,10 @@ class StatisticSchoolReportTask def call School.find_each do |school| evaluate_count = Game.joins(:challenge) - .joins('LEFT JOIN members ON members.user_id = games.user_id') + .joins('LEFT JOIN course_members ON course_members.user_id = games.user_id') .joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = challenges.shixun_id') .joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4') - .joins('LEFT JOIN courses ON hc.course_id = courses.id AND members.course_id = courses.id') + .joins('LEFT JOIN courses ON hc.course_id = courses.id AND course_members.course_id = courses.id') .where(courses: { school_id: school.id }) .sum(:evaluate_count) 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/courses/shared/_import_course_member_modal.html.erb b/app/views/admins/courses/shared/_import_course_member_modal.html.erb new file mode 100644 index 000000000..d52a60b09 --- /dev/null +++ b/app/views/admins/courses/shared/_import_course_member_modal.html.erb @@ -0,0 +1,30 @@ + \ 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 new file mode 100644 index 000000000..49b38e31a --- /dev/null +++ b/app/views/admins/department_applies/index.html.erb @@ -0,0 +1,18 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('部门审批') %> +<% end %> + +
+ <%= form_tag(admins_department_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_department_applies_path(keyword:nil),class:"btn btn-default",remote:true %> + <% end %> +
+ +
+ <%= render(partial: 'admins/department_applies/shared/list', locals: { applies: @depart_applies }) %> +
+ +<%= render(partial: 'admins/shared/admin_common_refuse_modal') %> +<%= render 'admins/departments/shared/merge_department_modal' %> \ No newline at end of file diff --git a/app/views/admins/department_applies/index.js.erb b/app/views/admins/department_applies/index.js.erb new file mode 100644 index 000000000..8e11b834c --- /dev/null +++ b/app/views/admins/department_applies/index.js.erb @@ -0,0 +1 @@ +$(".department-applies-list-container").html("<%= j render partial: "admins/department_applies/shared/list",locals: {applies:@depart_applies} %>") \ 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 new file mode 100644 index 000000000..0a1d803be --- /dev/null +++ b/app/views/admins/department_applies/shared/_list.html.erb @@ -0,0 +1,39 @@ + + + + + + + + + + + + + <% if applies.present? %> + <% applies.each do |apply| %> + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
ID部门名称单位名称创建者<%= sort_tag('创建于', name: 'created_at', path: admins_department_applies_path) %>操作
<%= apply.id %> <%= 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,tip:"unapplied", element: ".department-apply-#{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 } %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %> \ No newline at end of file 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/identity_authentications/index.html.erb b/app/views/admins/identity_authentications/index.html.erb index 38b7dfd63..89c3d58f9 100644 --- a/app/views/admins/identity_authentications/index.html.erb +++ b/app/views/admins/identity_authentications/index.html.erb @@ -25,6 +25,10 @@ <% end %> +
+ <%= javascript_void_link '批量同意', class: 'btn btn-outline-primary btn-sm batch-agree-btn' %> +
+
<%= render(partial: 'admins/identity_authentications/shared/list', locals: { applies: @applies }) %>
diff --git a/app/views/admins/identity_authentications/shared/_list.html.erb b/app/views/admins/identity_authentications/shared/_list.html.erb index f6aa53dd1..c40d681ec 100644 --- a/app/views/admins/identity_authentications/shared/_list.html.erb +++ b/app/views/admins/identity_authentications/shared/_list.html.erb @@ -3,6 +3,12 @@ + <% unless is_processed %> + + <% end %> @@ -14,12 +20,14 @@ <% end %> - <% if is_processed %> - + + + <% else %> - + + <% end %> @@ -28,6 +36,9 @@ <% applies.each do |apply| %> <% user = apply.user %> + <% unless is_processed %> + + <% end %> + <% else %> - + 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| %> +
+ <%= check_box_tag('all-check', 1, false, id: nil, class: 'batch-all-check-box', + data: { toggle: 'tooltip', title: '全选' }) %> + 头像 姓名 身份证号 时间拒绝原因时间拒绝原因 状态操作操作时间操作
<%= check_box_tag('ids[]', apply.id, false, id: nil, class: 'batch-check-box') %> <%= link_to "/users/#{user.login}", class: 'identity-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %> @@ -53,6 +64,11 @@ <% if is_processed %> <%= overflow_hidden_span apply.remarks, width: 140 %> <%= apply.status_text %> + <% if apply.status == 1 %> + <%= agree_link '撤销', revoke_admins_identity_authentication_path(apply, element: ".identity-authentication-#{apply.id}"), 'data-confirm': '是否确认撤销认证??' %> + <% end %> + <%= agree_link '同意', agree_admins_identity_authentication_path(apply, element: ".identity-authentication-#{apply.id}"), 'data-confirm': '确认审核通过?' %> 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') %>
+ + + + + + + + + <% 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/professional_authentications/index.html.erb b/app/views/admins/professional_authentications/index.html.erb index 32eaa47bd..436fc731f 100644 --- a/app/views/admins/professional_authentications/index.html.erb +++ b/app/views/admins/professional_authentications/index.html.erb @@ -25,6 +25,10 @@ <% end %> +
+ <%= javascript_void_link '批量同意', class: 'btn btn-outline-primary btn-sm batch-agree-btn' %> +
+
<%= render(partial: 'admins/professional_authentications/shared/list', locals: { applies: @applies }) %>
diff --git a/app/views/admins/professional_authentications/shared/_list.html.erb b/app/views/admins/professional_authentications/shared/_list.html.erb index fd7685f98..79cf31aad 100644 --- a/app/views/admins/professional_authentications/shared/_list.html.erb +++ b/app/views/admins/professional_authentications/shared/_list.html.erb @@ -3,12 +3,18 @@ + <% unless is_processed %> + + <% end %> - + <% unless is_processed %> - @@ -17,8 +23,9 @@ <% if is_processed %> + <% else %> - + <% end %> @@ -27,6 +34,9 @@ <% applies.each do |apply| %> <% user = apply.user %> + <% unless is_processed %> + + <% end %> + <% else %> <% end %> 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 %> - + diff --git a/app/views/admins/schools/index.html.erb b/app/views/admins/schools/index.html.erb new file mode 100644 index 000000000..0dd5b0bc5 --- /dev/null +++ b/app/views/admins/schools/index.html.erb @@ -0,0 +1,16 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('单位列表') %> +<% end %> + +
+ <%= form_tag(admins_schools_path, method: :get, class: 'form-inline search-form flex-1', 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': '搜索中...') %> + <% end %> + + <%#= javascript_void_link '新建单位', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-school-modal' } %> +
+ +
+ <%= render partial: 'admins/schools/shared/list', locals: { schools: @schools } %> +
\ No newline at end of file diff --git a/app/views/admins/schools/index.js.erb b/app/views/admins/schools/index.js.erb new file mode 100644 index 000000000..41a2454be --- /dev/null +++ b/app/views/admins/schools/index.js.erb @@ -0,0 +1 @@ +$('.school-list-container').html("<%= j(render partial: 'admins/schools/shared/list', locals: { schools: @schools }) %>"); \ No newline at end of file diff --git a/app/views/admins/schools/shared/_list.html.erb b/app/views/admins/schools/shared/_list.html.erb new file mode 100644 index 000000000..74df29cee --- /dev/null +++ b/app/views/admins/schools/shared/_list.html.erb @@ -0,0 +1,48 @@ +
+ <%= check_box_tag('all-check', 1, false, id: nil, class: 'batch-all-check-box', + data: { toggle: 'tooltip', title: '全选' }) %> + 头像 姓名学校/单位学校/单位 职称 + 照片 拒绝原因 状态操作操作操作
<%= check_box_tag('ids[]', apply.id, false, id: nil, class: 'batch-check-box') %> <%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %> @@ -51,14 +61,19 @@ <% if is_processed %> <%= overflow_hidden_span apply.remarks, width: 140 %> <%= apply.status_text %> + <% if apply.status == 1 %> + <%= agree_link '撤销', revoke_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}"), 'data-confirm': '是否确认撤销认证??' %> + <% end %> + - <%= agree_link '同意', agree_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}"), 'data-confirm': '确认审核通过?' %> + <%= agree_link '同意', agree_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}"), 'data-confirm': '确认审核通过?', 'data-disable-with': "提交中..." %> <%= javascript_void_link('拒绝', class: 'action refuse-action', data: { toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id, url: refuse_admins_professional_authentication_path(apply, element: ".professional-authentication-#{apply.id}") - }) %> + }, 'data-disable-with': "拒绝中...") %>
<%= 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') %>
+ + + + + + + + + + + + + + + + + <% if schools.present? %> + <% schools.each do |school| %> + + + + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
IDLOGO标识码单位名称地区城市详细地址<%= sort_tag('用户数', name: 'users_count', path: admins_schools_path) %>部门数<%= sort_tag('创建时间', name: 'created_at', path: admins_schools_path) %>操作
<%= school.id %> + <% if Util::FileManage.exists?(school) %> + <%= image_tag(Util::FileManage.source_disk_file_url(school).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image') %> + <% else %> + <%= content_tag(:span, '--', class: 'text-secondary') %> + <% end %> + <%= display_text school.identifier %><%= school.name %><%= school.province %><%= school.city %><%= school.address %><%= school.users_count %><%= @department_count.fetch(school.id, 0) %><%= school.created_at&.strftime('%Y-%m-%d %H:%M') %> + <%= delete_link '删除', admins_school_path(school, element: ".school-item-#{school.id}"), class: 'delete-school-action' %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %> \ No newline at end of file diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index a0e26d84e..2d9461f45 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -31,6 +31,7 @@
  • <%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %> +
  • <%= sidebar_item(admins_schools_path, '单位列表', icon: 'university', controller: 'admins-schools') %>
  • <%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %>
  • <% end %> @@ -56,15 +57,34 @@ <%= 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: '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') %>
  • -
  • <%= sidebar_item(admins_project_package_applies_path, '众包需求发布', icon: 'joomla', controller: 'admins-project_package_applies') %>
  • -
  • <%= sidebar_item(admins_video_applies_path, '视频发布', icon: 'film', controller: 'admins-video_applies') %>
  • +
  • <%= 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') %>
  • +
  • <%= sidebar_item(admins_project_package_applies_path, '众包需求发布', icon: 'joomla', controller: 'admins-project_package_applies') %>
  • +
  • <%= sidebar_item(admins_video_applies_path, '视频发布', icon: 'film', controller: 'admins-video_applies') %>
  • + <% end %> + - <% 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/shared/modal/_message_modal.html.erb b/app/views/admins/shared/modal/_message_modal.html.erb index 94454ca2d..17c02ea14 100644 --- a/app/views/admins/shared/modal/_message_modal.html.erb +++ b/app/views/admins/shared/modal/_message_modal.html.erb @@ -11,7 +11,7 @@ 保存成功 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/users/index.html.erb b/app/views/admins/users/index.html.erb index fa6d67a64..4b8307a7a 100644 --- a/app/views/admins/users/index.html.erb +++ b/app/views/admins/users/index.html.erb @@ -12,7 +12,7 @@
    - <% identity_options = [['全部', '']] + UserExtension.identities.map { |k, v| [I18n.t("user.identity.#{k}"), v] } %> + <% identity_options = [['全部', ''], ['教师', 0], ['学生', 1], ['专业人士', 2]] %> <%= select_tag(:identity, options_for_select(identity_options), class: 'form-control') %>
    @@ -28,6 +28,7 @@ <% end %> <%= javascript_void_link '导入用户', class: 'btn btn-secondary btn-sm', data: { toggle: 'modal', target: '.admin-import-user-modal'} %> + <%= javascript_void_link '导入课堂成员', class: 'btn btn-secondary btn-sm ml-2', data: { toggle: 'modal', target: '.admin-import-course-member-modal'} %>
    @@ -35,4 +36,7 @@
    <%= render partial: 'admins/users/shared/reward_grade_modal' %> -<%= render partial: 'admins/users/shared/import_user_modal' %> \ No newline at end of file +<%= render partial: 'admins/users/shared/import_user_modal' %> + + +<%= render partial: 'admins/courses/shared/import_course_member_modal' %> \ No newline at end of file diff --git a/app/views/admins/users/shared/_import_user_modal.html.erb b/app/views/admins/users/shared/_import_user_modal.html.erb index ff3c725b9..b0d3c9a77 100644 --- a/app/views/admins/users/shared/_import_user_modal.html.erb +++ b/app/views/admins/users/shared/_import_user_modal.html.erb @@ -14,8 +14,8 @@ 文件
    - - + +
    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/ecs/course_evaluations/average_score_import_template.xlsx.axlsx b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx index 900ff5888..934e1c4be 100644 --- a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx +++ b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx @@ -13,7 +13,7 @@ wb.styles do |style| name = course_evaluation.name items_size = course_evaluation.ec_course_evaluation_subitems.count - sheet.add_row name, style: bg_style + sheet.add_row [name], style: bg_style sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))] data = [] diff --git a/app/views/ecs/course_evaluations/index.json.jbuilder b/app/views/ecs/course_evaluations/index.json.jbuilder index e1c63d44d..b120bccc2 100644 --- a/app/views/ecs/course_evaluations/index.json.jbuilder +++ b/app/views/ecs/course_evaluations/index.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation', as: :ec_course_evaluation diff --git a/app/views/ecs/course_evaluations/show.json.jbuilder b/app/views/ecs/course_evaluations/show.json.jbuilder index b03ddc076..f67053183 100644 --- a/app/views/ecs/course_evaluations/show.json.jbuilder +++ b/app/views/ecs/course_evaluations/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation +json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation diff --git a/app/views/ecs/course_evaluations/slimmer.json.jbuilder b/app/views/ecs/course_evaluations/slimmer.json.jbuilder index 929cfe7be..6e0faef3e 100644 --- a/app/views/ecs/course_evaluations/slimmer.json.jbuilder +++ b/app/views/ecs/course_evaluations/slimmer.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation_slim', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation diff --git a/app/views/ecs/course_targets/index.json.jbuilder b/app/views/ecs/course_targets/index.json.jbuilder index 6590ecc10..9ec4af823 100644 --- a/app/views/ecs/course_targets/index.json.jbuilder +++ b/app/views/ecs/course_targets/index.json.jbuilder @@ -1,2 +1,2 @@ -json.course_targets @course_targets, partial: 'shared/course_target', as: :ec_course_target +json.course_targets @course_targets, partial: 'ecs/course_targets/shared/course_target', as: :ec_course_target diff --git a/app/views/ecs/course_targets/index.xlsx.axlsx b/app/views/ecs/course_targets/index.xlsx.axlsx index a188ad95c..ef4215b03 100644 --- a/app/views/ecs/course_targets/index.xlsx.axlsx +++ b/app/views/ecs/course_targets/index.xlsx.axlsx @@ -15,7 +15,7 @@ wb.styles do |style| name = "#{@_current_course.name}课程目标" wb.add_worksheet(name: name) do |sheet| - sheet.add_row name, style: title_style + sheet.add_row [name], style: title_style sheet.add_row [] sheet.add_row [] diff --git a/app/views/ecs/ec_courses/search.json.jbuilder b/app/views/ecs/ec_courses/search.json.jbuilder index fc22586d7..cf00a2b98 100644 --- a/app/views/ecs/ec_courses/search.json.jbuilder +++ b/app/views/ecs/ec_courses/search.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.ec_courses @ec_courses, partial: 'shared/ec_course_slim', as: :ec_course \ No newline at end of file +json.ec_courses @ec_courses, partial: 'ecs/ec_courses/shared/ec_course_slim', as: :ec_course \ No newline at end of file diff --git a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder index 6fbbf249b..ffb83ed23 100644 --- a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder @@ -1,3 +1,3 @@ json.count @graduation_requirements.size -json.graduation_requirements @graduation_requirements, partial: 'shared/ec_graduation_requirement', as: :ec_graduation_requirement +json.graduation_requirements @graduation_requirements, partial: '/ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement diff --git a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx index aeb802329..9a2081861 100644 --- a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx +++ b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx @@ -6,15 +6,15 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求及指标点') do |sheet| - sheet.add_row '毕业要求及指标点', style: title_style + sheet.add_row ['毕业要求及指标点'], style: title_style sheet.add_row [] - sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业代码', major.code.to_s + ' '], style: ec_year_style sheet.add_row ['专业名称', major.name], style: ec_year_style sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style @@ -32,12 +32,15 @@ wb.styles do |style| end items_size = requirement.ec_graduation_subitems.size - sheet.merge_cells("A#{index}:A#{index + items_size}") - sheet.merge_cells("B#{index}:B#{index + items_size}") + if items_size.zero? + sheet.add_row [requirement_content, ''], style: content_style + else + sheet.merge_cells("A#{index + 1}:A#{index + items_size}") + end index += items_size end - sheet.column_widths [400, 400] + sheet.column_widths 100, 100 end end \ No newline at end of file diff --git a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder index 562c255a9..d3a8db1fc 100644 --- a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder @@ -1,2 +1,2 @@ -json.partial! 'shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement +json.partial! 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement diff --git a/app/views/ecs/ec_major_schools/index.json.jbuilder b/app/views/ecs/ec_major_schools/index.json.jbuilder index 0924b71ea..312abd26b 100644 --- a/app/views/ecs/ec_major_schools/index.json.jbuilder +++ b/app/views/ecs/ec_major_schools/index.json.jbuilder @@ -3,7 +3,7 @@ json.count @count # 示例专业 json.template_ec_major_school do - json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school + json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school if @template_major_school end # 专业 @@ -11,5 +11,5 @@ json.ec_major_schools @major_schools do |ec_major_school| json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school # 专业管理员 - json.major_managers ec_major_school.users, partial: 'ecs/ec_major_schools/shared/ec_major_school', as: :user + json.major_managers ec_major_school.users, partial: 'users/user_simple', as: :user end diff --git a/app/views/ecs/ec_major_schools/show.json.jbuilder b/app/views/ecs/ec_major_schools/show.json.jbuilder new file mode 100644 index 000000000..7c911d824 --- /dev/null +++ b/app/views/ecs/ec_major_schools/show.json.jbuilder @@ -0,0 +1,6 @@ +json.extract! @major, :id, :code, :name, :template_major +json.school_id @major.school.id +json.school_name @major.school.name + +can_manager = @major.manager?(current_user) || @major.school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/app/views/ecs/ec_majors/index.json.jbuilder b/app/views/ecs/ec_majors/index.json.jbuilder index 34ee9a907..df3373fed 100644 --- a/app/views/ecs/ec_majors/index.json.jbuilder +++ b/app/views/ecs/ec_majors/index.json.jbuilder @@ -1,2 +1,7 @@ json.count @count -json.es_majors @ec_majors, partial: 'ecs/majors/shared/ec_major', as: :ec_major +json.ec_majors do + json.array! @ec_majors.each do |major| + json.extract! major, :id, :name, :code + json.selected @major_ids.include?(major.id) + end +end diff --git a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder index 83414d2f4..61992d8e1 100644 --- a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder @@ -1,3 +1,3 @@ json.extract! ec_training_objective, :id, :content -json.ec_training_items ec_training_objective.ec_training_subitems, partial: 'ec_training_subitem', as: :ec_training_subitem +json.ec_training_items ec_training_objective.ec_training_subitems, partial: '/ecs/ec_training_objectives/shared/ec_training_subitem', as: :ec_training_subitem diff --git a/app/views/ecs/ec_training_objectives/show.json.jbuilder b/app/views/ecs/ec_training_objectives/show.json.jbuilder index a37fa1c09..00825be4c 100644 --- a/app/views/ecs/ec_training_objectives/show.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_training_objective', ec_training_objective: @training_objective +json.partial! '/ecs/ec_training_objectives/shared/ec_training_objective', ec_training_objective: @training_objective diff --git a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx index 4746be0ea..130e80e6b 100644 --- a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx +++ b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx @@ -6,11 +6,11 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', border: { style: :thin, color: '000000' }, alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '培养目标及目标分解') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['培养目标及目标分解'], style: title_style sheet.add_row [] sheet.add_row [] @@ -27,6 +27,6 @@ wb.styles do |style| end items_size = training_objective.ec_training_subitems.size - sheet.merge_cells("A9:A#{9 + items_size}") + sheet.merge_cells("A9:A#{9 + items_size - 1}") end end \ No newline at end of file diff --git a/app/views/ecs/ec_years/index.json.jbuilder b/app/views/ecs/ec_years/index.json.jbuilder index c5c89cd06..b0a8985b2 100644 --- a/app/views/ecs/ec_years/index.json.jbuilder +++ b/app/views/ecs/ec_years/index.json.jbuilder @@ -8,7 +8,16 @@ json.ec_years do json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0) json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0) json.course_count @course_count_map.fetch(ec_year.id, 0) - json.course_target_count @course_target_count_map.fetch(ec_year.id, 0) - json.graduation_subitem_count @graduation_subitem_count_map.fetch(ec_year.id, 0) + + course_target = @course_target_count_map.fetch(ec_year.id, 0) + graduation_subitem = @graduation_subitem_count_map.fetch(ec_year.id, 0) + achieved_course = achieved_graduation_course_count(ec_year) + achieved_objective = achieved_graduation_objective_count(ec_year) + + json.course_target_count course_target + json.graduation_subitem_count graduation_subitem + json.achieved_graduation_course_count achieved_course + json.achieved_graduation_objective_count achieved_objective + json.status graduation_subitem == achieved_objective ? 'achieved' : 'not_achieved' end end \ No newline at end of file diff --git a/app/views/ecs/ec_years/show.json.jbuilder b/app/views/ecs/ec_years/show.json.jbuilder new file mode 100644 index 000000000..ba8333086 --- /dev/null +++ b/app/views/ecs/ec_years/show.json.jbuilder @@ -0,0 +1,13 @@ +json.extract! @year, :id, :year + +major = @year.ec_major_school +json.major_id major.id +json.major_name major.name +json.major_code major.code + +school = major.school +json.school_id school.id +json.school_name school.name + +can_manager = major.manager?(current_user) || school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/app/views/ecs/graduation_course_supports/create.json.jbuilder b/app/views/ecs/graduation_course_supports/create.json.jbuilder index c05024911..d8749a5dc 100644 --- a/app/views/ecs/graduation_course_supports/create.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/create.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem +json.partial! 'ecs/graduation_course_supports/shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem diff --git a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder index 1ffe12ec4..ced8a5c72 100644 --- a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder @@ -2,4 +2,5 @@ json.extract! ec_graduation_subitem, :id, :position, :content, :ec_graduation_re json.graduation_requirement_position ec_graduation_subitem.ec_graduation_requirement.position -json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ec_course_support', as: :ec_course_support +json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ecs/graduation_course_supports/shared/ec_course_support', as: :ec_course_support +json.weights_total ec_graduation_subitem.ec_course_supports.to_a.sum(&:weights) diff --git a/app/views/ecs/graduation_course_supports/show.json.jbuilder b/app/views/ecs/graduation_course_supports/show.json.jbuilder index a9e4bdc22..495f9c6a9 100644 --- a/app/views/ecs/graduation_course_supports/show.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/show.json.jbuilder @@ -1,3 +1,3 @@ json.course_count @course_count -json.graduation_subitems @graduation_subitems, partial: 'shared/ec_graduation_subitem', as: :ec_graduation_subitem +json.graduation_subitems @graduation_subitems, partial: 'ecs/graduation_course_supports/shared/ec_graduation_subitem', as: :ec_graduation_subitem json.count @graduation_subitems.size diff --git a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx index fd1a44935..ae81d931b 100644 --- a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx +++ b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx @@ -9,13 +9,13 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }, border: { style: :thin, color: '000000' }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center, vertical: :center }, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) - tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A') + tip_style = style.add_style(sz: 11, height: 16, color: Axlsx::Color.new(rgb: 'FFFFA07A')) wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet| - sheet.add_row '课程体系VS毕业要求', style: title_style - sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))] + sheet.add_row ['课程体系VS毕业要求'], style: title_style + sheet.merge_cells sheet.rows.first.cells[(1..(3 + max_support_length - 1))] sheet.add_row [] @@ -25,8 +25,8 @@ wb.styles do |style| sheet.add_row ['注:有对应关系的课程名称下方为其权重系数,一个指标点的权重系数之和必须等于1'], style: tip_style sheet.add_row ['注:“★” 表示关联度高'] - sheet.merge_cells wb.rows[5].cells[(1..(3 + max_support_length - 1))] - sheet.merge_cells wb.rows[6].cells[(1..(3 + max_support_length - 1))] + sheet.merge_cells sheet.rows[5].cells[(1..(3 + max_support_length - 1))] + sheet.merge_cells sheet.rows[6].cells[(1..(3 + max_support_length - 1))] sheet.add_row [] @@ -34,9 +34,9 @@ wb.styles do |style| data[last_column_index] = '课程数量' sheet.add_row data, style: label_style course_columns = max_support_length.times.map { |i| "课程#{i + 1}" } - sheet.add_row %w('一级 二级') + course_columns + ['∑目标值'], style: label_style + sheet.add_row %w(一级 二级) + course_columns + ['∑目标值'], style: label_style sheet.merge_cells("A9:B9") - sheet.merge_cells wb.rows[8].cells[(3..(3 + max_support_length - 1))] + # sheet.merge_cells sheet.rows[8].cells[(3..(3 + max_support_length - 1))] current_row = 11 graduation_subitems.group_by(&:ec_graduation_requirement).each do |requirement, items| @@ -61,11 +61,11 @@ wb.styles do |style| sheet.add_row course_data, style: styles sheet.add_row weight_data, style: styles - sheet.merge_cells("B#{current_row - 1}:B#{current_row}") + sheet.merge_cells("B#{current_row}:B#{current_row + 1}") current_row += 2 end - sheet.merge_cells("A#{start_row - 1}:B#{current_row - 1}") + sheet.merge_cells("A#{start_row}:A#{current_row - 1}") end end end \ No newline at end of file diff --git a/app/views/ecs/graduation_subitems/index.json.jbuilder b/app/views/ecs/graduation_subitems/index.json.jbuilder new file mode 100644 index 000000000..0a1235b1d --- /dev/null +++ b/app/views/ecs/graduation_subitems/index.json.jbuilder @@ -0,0 +1,8 @@ +json.graduation_subitems do + json.array! @graduation_subitems do |graduation_subitem| + json.extract! graduation_subitem, :id, :position, :content + json.graduation_requirement_position graduation_subitem.ec_graduation_requirement.position + end +end + +json.count @graduation_subitems.size \ No newline at end of file diff --git a/app/views/ecs/homes/index.json.jbuilder b/app/views/ecs/homes/index.json.jbuilder index 9bf21f056..8546f6c4a 100644 --- a/app/views/ecs/homes/index.json.jbuilder +++ b/app/views/ecs/homes/index.json.jbuilder @@ -13,4 +13,4 @@ json.school do json.name current_school.name end -json.school_managers @school_managers, partial: 'ecs/shared/user', as: :user +json.school_managers @school_managers, partial: 'users/user_simple', as: :user diff --git a/app/views/ecs/major_managers/create.json.jbuilder b/app/views/ecs/major_managers/create.json.jbuilder deleted file mode 100644 index ff7ff01e5..000000000 --- a/app/views/ecs/major_managers/create.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/reach_evaluations/show.xlsx.axlsx b/app/views/ecs/reach_evaluations/show.xlsx.axlsx index a62e4f6c2..a79d059a3 100644 --- a/app/views/ecs/reach_evaluations/show.xlsx.axlsx +++ b/app/views/ecs/reach_evaluations/show.xlsx.axlsx @@ -10,7 +10,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['达成度-毕业要求综合评价报表'], style: title_style sheet.merge_cells("A1:D1") sheet.add_row [] diff --git a/app/views/ecs/requirement_support_objectives/show.json.jbuilder b/app/views/ecs/requirement_support_objectives/show.json.jbuilder index 1ba783304..642a5f10c 100644 --- a/app/views/ecs/requirement_support_objectives/show.json.jbuilder +++ b/app/views/ecs/requirement_support_objectives/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem -json.requirement_support_objectives @requirement_support_objectives, partial: 'shared/requirement_support_objective', as: :requirement_support_objective +json.requirement_support_objectives @requirement_support_objectives, partial: 'ecs/requirement_support_objectives/shared/requirement_support_objective', as: :requirement_support_objective diff --git a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx index 934ad2941..6534ce36a 100644 --- a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx +++ b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx @@ -16,7 +16,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet| - sheet.add_row '毕业要求 vs 培养目标矩阵', style: title_style + sheet.add_row ['毕业要求 vs 培养目标矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..subitem_size)] diff --git a/app/views/ecs/score_levels/show.json.jbuilder b/app/views/ecs/score_levels/show.json.jbuilder index 0c8b76d86..dcdf63cdc 100644 --- a/app/views/ecs/score_levels/show.json.jbuilder +++ b/app/views/ecs/score_levels/show.json.jbuilder @@ -1 +1 @@ -json.score_levels @score_levels, partial: 'shared/ec_score_level', as: :ec_score_level +json.score_levels @score_levels, partial: 'ecs/score_levels/shared/ec_score_level', as: :ec_score_level diff --git a/app/views/ecs/students/show.json.jbuilder b/app/views/ecs/students/show.json.jbuilder index 352970055..468a1cfe3 100644 --- a/app/views/ecs/students/show.json.jbuilder +++ b/app/views/ecs/students/show.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.students @students, partial: 'shared/ec_year_student', as: :ec_year_student \ No newline at end of file +json.students @students, partial: 'ecs/students/shared/ec_year_student', as: :ec_year_student \ No newline at end of file diff --git a/app/views/ecs/subitem_support_standards/show.json.jbuilder b/app/views/ecs/subitem_support_standards/show.json.jbuilder index 94fd6c5a0..a92fe7000 100644 --- a/app/views/ecs/subitem_support_standards/show.json.jbuilder +++ b/app/views/ecs/subitem_support_standards/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem -json.subitem_support_standards @subitem_support_standards, partial: 'shared/subitem_support_standard', as: :subitem_support_standard +json.subitem_support_standards @subitem_support_standards, partial: 'ecs/subitem_support_standards/shared/subitem_support_standard', as: :subitem_support_standard diff --git a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx index e12f517f3..8329a27ee 100644 --- a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx +++ b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx @@ -17,7 +17,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet| - sheet.add_row '毕业要求 vs 通用标准矩阵', style: title_style + sheet.add_row ['毕业要求 vs 通用标准矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..standards_size)] diff --git a/app/views/ecs/users/index.json.jbuilder b/app/views/ecs/users/index.json.jbuilder new file mode 100644 index 000000000..0109b9ca0 --- /dev/null +++ b/app/views/ecs/users/index.json.jbuilder @@ -0,0 +1,12 @@ +json.count @count +json.users do + json.array! @users.each do |user| + json.id user.id + json.name user.real_name + json.identity user.identity + json.school_name user.school_name + json.department_name user.department_name + json.phone Util.conceal(user.phone, :phone) + json.manager @manager_ids.include?(user.id) + end +end \ 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/homework_commons/works_list.json.jbuilder b/app/views/homework_commons/works_list.json.jbuilder index 08c269670..e567ea79a 100644 --- a/app/views/homework_commons/works_list.json.jbuilder +++ b/app/views/homework_commons/works_list.json.jbuilder @@ -4,6 +4,7 @@ json.partial! "homework_btn_check", locals: {identity: @user_course_identity, ho json.partial! "student_btn_check", locals: {identity: @user_course_identity, homework: @homework, work: @work} +json.update_score @homework.update_score(@user_course_identity) if @homework.homework_type == "practice" json.work_count @work_count json.all_member_count @all_member_count json.course_group_count @course.course_groups_count diff --git a/app/views/searchs/index.json.jbuilder b/app/views/searchs/index.json.jbuilder index 5fa0c2744..65c4d248c 100644 --- a/app/views/searchs/index.json.jbuilder +++ b/app/views/searchs/index.json.jbuilder @@ -6,6 +6,16 @@ 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 = /^[,。?:;‘’!“”—……、]/ + # 附件的替换 + atta_reg = /!\[.*]\(\/api\/attachments\/\d+\)/ + highlights[:description]&.first&.sub!(reg, '') + highlights[:description]&.map{|des| des.gsub!(atta_reg, '')} + highlights[:content]&.first&.sub!(reg, '') + highlights[:content]&.map{|des| des.gsub!(atta_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..79ce4b09c --- /dev/null +++ b/app/views/shixun_lists/index.json.jbuilder @@ -0,0 +1,27 @@ +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 = /^[,。?:;‘’!“”—……、]/ + # 附件的替换 + atta_reg = /!\[.*]\(\/api\/attachments\/\d+\)/ + + highlights[:description]&.first&.sub!(reg, '') + highlights[:description]&.map{|des| des.gsub!(atta_reg, '')} + highlights[:content]&.first&.sub!(reg, '') + highlights[:content]&.map{|des| des.gsub!(atta_reg, '')} + + json.title highlights.delete(:name)&.join('...') || obj.searchable_title + json.description highlights[:description]&.join('...') || Util.extract_content(obj.description)[0..300]&.sub!(atta_reg, '') + + 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 new file mode 100644 index 000000000..2f1d4905c --- /dev/null +++ b/app/views/shixuns/shixun_list.json.jbuilder @@ -0,0 +1,17 @@ +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.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/student_works/show.json.jbuilder b/app/views/student_works/show.json.jbuilder index 192e4d8ec..9bafbe93e 100644 --- a/app/views/student_works/show.json.jbuilder +++ b/app/views/student_works/show.json.jbuilder @@ -11,7 +11,7 @@ json.update_user_name @is_evaluation ? "匿名" : @work.update_user.try(:real_na json.update_atta @homework.late_duration && @is_author json.attachments @attachments do |atta| - json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} end unless @is_evaluation diff --git a/app/views/subjects/show.json.jbuilder b/app/views/subjects/show.json.jbuilder index 997e0c3d6..7febcd789 100644 --- a/app/views/subjects/show.json.jbuilder +++ b/app/views/subjects/show.json.jbuilder @@ -24,4 +24,10 @@ if @subject.excellent json.course_identity @user.course_identity(course) json.course_status subject_course_status course end + + if @subject.max_course_end_date.nil? || @subject.max_course_end_date < Date.today + json.student_count @subject.student_count + json.participant_count @subject.participant_count + json.has_participate @subject.has_participate? + end end \ No newline at end of file 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..b53574274 100644 --- a/app/views/tidings/_tiding.json.jbuilder +++ b/app/views/tidings/_tiding.json.jbuilder @@ -17,8 +17,11 @@ 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.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/courses/shared/_course.json.jbuilder b/app/views/users/courses/shared/_course.json.jbuilder index e917033da..8da80f372 100644 --- a/app/views/users/courses/shared/_course.json.jbuilder +++ b/app/views/users/courses/shared/_course.json.jbuilder @@ -5,6 +5,7 @@ json.members_count course.course_members_count # json.homework_commons_count course.homework_commons_count json.homework_commons_count get_tasks_count course json.attachments_count course.attachments.count +json.visits course.visits json.first_category_url module_url(course.course_modules.where(hidden: 0).order(position: :desc).first, course) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index 6189358ba..e18ccfe05 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -20,6 +20,7 @@ if @course json.group_info @course.teacher_group(@user.id) if @course_identity < Course::STUDENT end json.first_category_url module_url(@course.none_hidden_course_modules.first, @course) + json.course_is_end @course.is_end end if params[:school] 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/configuration.yml.example b/config/configuration.yml.example index e6d78f200..612011a7f 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -15,6 +15,9 @@ defaults: &defaults cate_id: '-1' callback_url: 'http://47.96.87.25:48080/api/callbacks/aliyun_vod.json' signature_key: 'test12345678' + wechat: + appid: 'test' + secret: 'test' development: <<: *defaults diff --git a/config/initializers/aliyun_vod_init.rb b/config/initializers/aliyun_vod_init.rb index 47b1dc6a3..9185eac20 100644 --- a/config/initializers/aliyun_vod_init.rb +++ b/config/initializers/aliyun_vod_init.rb @@ -4,7 +4,7 @@ aliyun_vod_config = {} begin config = Rails.application.config_for(:configuration) aliyun_vod_config = config['aliyun_vod'] - raise 'oauth wechat config missing' if aliyun_vod_config.blank? + raise 'aliyun vod config missing' if aliyun_vod_config.blank? rescue => ex raise ex if Rails.env.production? 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/initializers/util_wechat_init.rb b/config/initializers/util_wechat_init.rb new file mode 100644 index 000000000..cb39afcaf --- /dev/null +++ b/config/initializers/util_wechat_init.rb @@ -0,0 +1,16 @@ +wechat_config = {} + +begin + config = Rails.application.config_for(:configuration) + wechat_config = config['wechat'] + raise 'wechat config missing' if wechat_config.blank? +rescue => ex + raise ex if Rails.env.production? + + puts %Q{\033[33m [warning] wechat config or configuration.yml missing, + please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} + wechat_config = {} +end + +Util::Wechat.appid = wechat_config['appid'] +Util::Wechat.secret = wechat_config['secret'] 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..557f3f79b 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -10,7 +10,7 @@ "2_1_end": "你提交的职业认证申请,审核已通过" "2_2_end": "你提交的职业认证申请,审核未通过
    原因:%{reason}" CancelUserAuthentication_end: "取消了你的实名认证:%s %s" - CancelUserProCertification_end: "取消了你的实名认证:%s %s" + CancelUserProCertification_end: "取消了你的职业认证:%s %s" JoinCourse: "9_end": "申请加入课堂:%s(教师)" "7_end": "申请加入课堂:%s(助教)" @@ -19,7 +19,7 @@ "9_2_end": "你提交的加入课堂申请:%s(教师), 审核未通过" "7_1_end": "你提交的加入课堂申请:%s(助教), 审核已通过" "7_2_end": "你提交的加入课堂申请:%s(助教), 审核未通过" - StudentJoinCourse_end: "加入了课堂:%s(学生)" + StudentJoinCourse_end: "%s 加入了课堂:%s(学生)" TeacherJoinCourse: "2_end": "%s将你加入课堂:%s(教师)" "3_end": "%s将你加入课堂:%s(助教)" @@ -202,6 +202,7 @@ 2_end: "别人对你的匿评发起的申诉申请:%s,审核未通过" StudentWork: Apply_end: "发起了匿评申诉申请:%s" + HomeworkCommon_end: "发起了匿评申诉申请:%s" System_end: "有人对你的匿评发起了申诉:%s" Department_end: "你选填的二级单位:%s(%s)因不符合规范,已被系统删除.请重新选择" Library: @@ -226,3 +227,4 @@ 1_end: "你提交的发布视频申请:%s,审核已通过" 2_end: "你提交的发布视频申请:%s,审核未通过
    原因:%{reason}" PublicCourseStart_end: "你报名参与的开放课程:%s,将于%s正式开课" + SubjectStartCourse_end: "您创建的开放课程:%s 已达到开课人数要求。您可以在24小时内自主开设新一期课程。如果超过24小时未开课,平台将自动开课并复制您上一期的课程内容。" diff --git a/config/locales/users/zh-CN.yml b/config/locales/users/zh-CN.yml index 48b8ca075..dc49b6617 100644 --- a/config/locales/users/zh-CN.yml +++ b/config/locales/users/zh-CN.yml @@ -13,7 +13,9 @@ professional: 专业人士 developer: 从业者 enterprise: 组织 + unselect: 未选择 "0": 教师 "1": 学生 "2": 专业人士 - "3": 专业人士 \ No newline at end of file + "3": 从业者 + "4": 组织 \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 2fe1cf5ec..1c765bc7b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -57,12 +57,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] @@ -161,6 +163,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 @@ -173,7 +176,10 @@ Rails.application.routes.draw do end end + resources :shixun_lists + resources :shixuns, param: :identifier do + collection do get :menus get :get_recommend_shixuns @@ -181,6 +187,7 @@ Rails.application.routes.draw do get :get_mirror_script post :apply_shixun_mirror get :download_file + get :shixun_lists end member do @@ -196,6 +203,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 @@ -277,6 +286,7 @@ Rails.application.routes.draw do post :up_member_position post :down_member_position get :right_banner + post :appointment end collection do @@ -355,6 +365,7 @@ Rails.application.routes.draw do get 'informs' post 'update_informs' post 'new_informs' + delete 'delete_informs' get 'online_learning' post 'join_excellent_course' get 'tasks_list' @@ -369,6 +380,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 +456,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 @@ -693,14 +713,15 @@ Rails.application.routes.draw do # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 scope module: :ecs do - resources :ec_major_schools, only: [] do + resources :ec_major_schools, only: [:show] do + resources :users, only: [:index] resources :major_managers, only: [:create, :destroy] - resources :ec_years, only: [:index, :create, :destroy] + resources :ec_years, only: [:index, :show, :create, :destroy] end resources :ec_years, only: [] do resource :ec_training_objectives, only: [:show, :create] - resources :ec_graduation_requirements, only: [:index, :create] + resources :ec_graduation_requirements, only: [:index, :create, :update, :destroy] resource :requirement_support_objectives, only: [:show, :create, :destroy] resource :subitem_support_standards, only: [:show, :create, :destroy] resource :students, only: [:show, :destroy] do @@ -719,6 +740,7 @@ Rails.application.routes.draw do resource :graduation_course_supports, only: [:show, :create] resource :reach_evaluation, only: [:show, :create] resource :reach_criteria, only: [:create] + resources :graduation_subitems, only: [:index] end resources :ec_courses, only: [] do @@ -777,10 +799,46 @@ Rails.application.routes.draw do end post 'callbacks/aliyun_vod', to: 'callbacks/aliyun_vods#create' + + 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 @@ -824,12 +882,22 @@ Rails.application.routes.draw do member do post :agree post :refuse + post :revoke + end + + collection do + post :batch_agree end end resources :professional_authentications, only: [:index] do member do post :agree post :refuse + post :revoke + end + + collection do + post :batch_agree end end resources :shixun_authorizations, only: [:index] do @@ -852,21 +920,44 @@ Rails.application.routes.draw do end resources :shixuns, only: [:index,:destroy] resources :shixun_settings, only: [:index,:update] + 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 + end resources :mirror_repositories, only: [:index, :new, :create, :edit, :update, :destroy] do collection do post :merge get :for_select end - resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy] end resources :choose_mirror_repositories, only: [:new, :create] + resources :schools, only: [:index, :destroy] resources :departments, only: [:index, :create, :edit, :update, :destroy] do resource :department_member, only: [:create, :update, :destroy] - 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/20190911080150_change_ec_course_supports.rb b/db/migrate/20190911080150_change_ec_course_supports.rb new file mode 100644 index 000000000..07c3a536d --- /dev/null +++ b/db/migrate/20190911080150_change_ec_course_supports.rb @@ -0,0 +1,11 @@ +class ChangeEcCourseSupports < ActiveRecord::Migration[5.2] + def change + add_column :ec_course_supports, :ec_graduation_subitem_id, :integer, index: true + + execute <<-SQL + UPDATE ec_course_supports ecs SET ec_graduation_subitem_id = ( + SELECT ec_graduation_subitem_id FROM ec_graduation_subitem_courses egsc WHERE egsc.ec_course_support_id = ecs.id + ) + SQL + 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/db/migrate/20190920073337_migrate_user_extension_index.rb b/db/migrate/20190920073337_migrate_user_extension_index.rb new file mode 100644 index 000000000..1d333bd99 --- /dev/null +++ b/db/migrate/20190920073337_migrate_user_extension_index.rb @@ -0,0 +1,6 @@ +class MigrateUserExtensionIndex < ActiveRecord::Migration[5.2] + def change + remove_index :user_extensions, :school_id + add_index :user_extensions, [:school_id, :user_id] + end +end diff --git a/db/migrate/20190921010411_add_course_member_to_subjects.rb b/db/migrate/20190921010411_add_course_member_to_subjects.rb new file mode 100644 index 000000000..76df05604 --- /dev/null +++ b/db/migrate/20190921010411_add_course_member_to_subjects.rb @@ -0,0 +1,6 @@ +class AddCourseMemberToSubjects < ActiveRecord::Migration[5.2] + def change + add_column :subjects, :student_count, :integer, :default => 0 + add_column :subjects, :participant_count, :integer, :default => 0 + end +end diff --git a/db/migrate/20190921015840_create_subject_appointments.rb b/db/migrate/20190921015840_create_subject_appointments.rb new file mode 100644 index 000000000..68c924de7 --- /dev/null +++ b/db/migrate/20190921015840_create_subject_appointments.rb @@ -0,0 +1,10 @@ +class CreateSubjectAppointments < ActiveRecord::Migration[5.2] + def change + create_table :subject_appointments do |t| + t.references :subject, index: true + t.references :user, index: true + + t.timestamps + end + end +end diff --git a/dump.rdb b/dump.rdb index 6673bf623..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 new file mode 100644 index 000000000..c26090e81 --- /dev/null +++ b/lib/tasks/public_course_sync.rake @@ -0,0 +1,154 @@ +#coding=utf-8 +# 执行示例 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 +# +# 这次学习很有收获,感谢老师提供这么好的资源和细心的服务🎉🎉🎉 +# + +desc "同步精品课数据" +namespace :public_classes do + if ENV['args'] + subject_id = ENV['args'].split(",")[0] # 对应课程的id + course_id = ENV['args'].split(",")[1] # 对应课堂的id + start_time = ENV['args'].split(",")[2] # 表示课程模块 + end_time = ENV['args'].split(",")[3] # 表示课程模块 + limit = ENV['args'].split(",")[4] # 限制导入的数量 + type = ENV['args'].split(",")[5] # 表示课程模块 + end + + + 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 + where stage_id in (select id from stages where subject_id=#{subject_id})) limit #{limit}").map(&:user_id) + puts "user_ids count is #{user_ids.count}" + if user_ids.present? + user_ids.each do |user_id| + puts user_id + begin + CourseMember.create!(course_id: course_id, user_id: user_id, role: 4) + rescue Exception => e + Rails.logger(e.message) + end + end + end + end + + task :test_user => :environment do + 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 + end + + + # 更新某个课程的某类时间 + # 执行示例 RAILS_ENV=production bundle exec rake public_course:time args=-1,2932,1,1 + task :time => :environment do + # course_id = ENV['args'].split(",")[0] # 对应课堂的id + # type = ENV['args'].split(",")[1] + + course = Course.find(course_id) + + case type.to_i + when 1 + # 讨论区 + messages = Message.where(board_id: course.boards) + messages.each do |message| + created_on = random_time start_time, end_time + puts created_on + message.update_columns(created_on: created_on, updated_on: created_on) + MessageDetail.where(message_id: message.id).each do |detail| + rand_created_on = random_time start_time, end_time + detail.update_columns(created_at: rand_created_on, updated_at: rand_created_on) + end + end + when 2 + # 作业 + course.homework_commons.each do |homework| + created_at = random_time(start_time, end_time) + publish_time = random_larger_time created_at, start_time, end_time + end_time = random_larger_time publish_time, start_time, end_time + updated_at = end_time + + 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) + end + when 3 + # 试卷 + course.exercises.each do |exercise| + created_at = random_time start_time, end_time + publish_time = random_larger_time created_at, start_time, end_time + end_time = random_larger_time publish_time, start_time, end_time + updated_at = end_time + + exercise.update_columns(publish_time: publish_time, end_time: end_time, created_at: created_at, updated_at: updated_at, exercise_status: 3) + end + when 4 + # 资源 + course.attachments.each do |atta| + created_on = random_time start_time, end_time + + atta.update_columns(is_publish: 1, created_on: created_on, publish_time: created_on) + end + end + + end + + task :create_homework_work => :environment do + course = Course.find(course_id) + course.practice_homeworks.each do |homework| + if homework.student_works.count == 0 + str = "" + CourseMember.students(course).each do |student| + str += "," if str != "" + str += "(#{homework.id},#{student.user_id}, '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}', '#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}')" + end + if str != "" + sql = "insert into student_works (homework_common_id, user_id, created_at, updated_at) values" + str + ActiveRecord::Base.connection.execute sql + end + end + end + end + + def min_swith(time) + puts time + return time < 9 ? "0#{time}" : time + end + + def random_time(start_time, end_time) + hour = (6..23).to_a.sample(1).first + min = rand(60) + sec = rand(60) + + start_time = Date.parse(start_time) + end_time = Date.parse(end_time) + date = (start_time..end_time).to_a.sample(1).first + + time = "#{date} #{min_swith(hour)}:#{min_swith(min)}:#{min_swith(sec)}" + + puts time + time + end + + def random_larger_time(time, start_time, end_time) + large_time = random_time(start_time, end_time) + while large_time <= time + large_time = random_time(start_time, end_time) + end + large_time + end +end \ No newline at end of file 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..a61e9dd26 --- /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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-09-21T15:26:10+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-09-03T08:55:53+08:00","size":2816,"digest":"7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423","integrity":"sha256-f/ESVocJv5f5iY/ockm3qPIA/x9I1TfYWvhyFfGHBCM="},"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js":{"logical_path":"application.js","mtime":"2019-09-21T15:26:10+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="},"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js":{"logical_path":"admin.js","mtime":"2019-09-21T15:28:08+08:00","size":4382031,"digest":"c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4","integrity":"sha256-yeXr5hkVSFUOJ1FBluoSXPu0AoIOwSWgyaz5nS03j+Q="},"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css":{"logical_path":"admin.css","mtime":"2019-09-21T14:49:04+08:00","size":840093,"digest":"59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38","integrity":"sha256-WcWfjK6L70qDWShsmFRYEQydA+oSFRZZXJiJQ/RxfDg="},"college-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css":{"logical_path":"college.css","mtime":"2019-09-16T13:56:09+08:00","size":579109,"digest":"38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437","integrity":"sha256-OPlT1rpbhdP6tjyzwrvw0FfMxkVNB8+q+sOwbaN7hDc="},"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.css":{"logical_path":"application.css","mtime":"2019-09-21T14:49:04+08:00","size":1988767,"digest":"646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3","integrity":"sha256-ZGsRWKTowfE+aE1v6QJavHX407pSVuRAgCwDmCIzdPM="}},"assets":{"admin.js":"admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js","admin.css":"admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.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-38f953d6ba5b85d3fab63cb3c2bbf0d057ccc6454d07cfaafac3b06da37b8437.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-646b1158a4e8c1f13e684d6fe9025abc75f8d3ba5256e440802c0398223374f3.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 46d740f5a..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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+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-14T17:22:43+08:00","size":444379,"digest":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","integrity":"sha256-rWFXkmwWIrpOHQPUePFUE2hSS/xG9R5C/g2UX37zI+Q="},"college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js":{"logical_path":"college.js","mtime":"2019-09-02T11:27:03+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-22T16:56:33+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-02T14:11:35+08:00","size":600706,"digest":"9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb","integrity":"sha256-nPvD15JZmh0N5ce4QgnhwrLmAzbw8B4Z8FgWY5GHCPs="}},"assets":{"admin.js":"admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js","admin.css":"admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.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-315d626b40fca41ae2670fb1700bfed6093f1ad56a3cc3cef00be02faedb0176.css","logo.png":"logo-7ff112568709bf97f9898fe87249b7a8f200ff1f48d537d85af87215f1870423.png","application.js":"application-9cfbc3d792599a1d0de5c7b84209e1c2b2e60336f0f01e19f0581663918708fb.js","application.css":"application-b12c6a987e49d1cda015d172244bc61badb8dd37ea38b74d864ba5d14b201d71.css"}} \ No newline at end of file diff --git a/public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css.gz b/public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css.gz deleted file mode 100644 index a0bad3156..000000000 Binary files a/public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css.gz and /dev/null differ diff --git a/public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css b/public/assets/admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css similarity index 80% rename from public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css rename to public/assets/admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css index 5105bbb28..7f47cf542 100644 --- a/public/assets/admin-521862c9da30ecc23745b70d7290a23ab2e86fdf39e89a1fc2c2642c16a0d7ef.css +++ b/public/assets/admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css @@ -17936,244 +17936,1469 @@ form.was-validated select:valid ~ .select2-container--bootstrap4 .select2-select margin-left: 10px; } -/* BASICS */ -/* line 3, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror { - /* Set height, width, borders, and global font properties here */ - font-family: monospace; - height: 300px; - color: black; - direction: ltr; +/*! + * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/) + * Author: boniface pereira + * Website: www.craftpip.com + * Contact: hey@craftpip.com + * + * Copyright 2013-2019 jquery-confirm + * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) + */ +@-webkit-keyframes jconfirm-spin { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } -/* PADDING */ -/* line 13, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-lines { - padding: 4px 0; - /* Vertical padding around content */ +@keyframes jconfirm-spin { + from { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } } -/* line 16, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror pre.CodeMirror-line, -.CodeMirror pre.CodeMirror-line-like { - padding: 0 4px; - /* Horizontal padding of content */ +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +body[class*=jconfirm-no-scroll-] { + overflow: hidden !important; } -/* line 21, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - background-color: white; - /* The little square between H and V scrollbars */ +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 99999999; + font-family: inherit; + overflow: hidden; } -/* GUTTER */ -/* line 27, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutters { - border-right: 1px solid #ddd; - background-color: #f7f7f7; - white-space: nowrap; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-bg { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + -webkit-transition: opacity .4s; + transition: opacity .4s; } -/* line 33, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-linenumber { - padding: 0 3px 0 5px; - min-width: 20px; - text-align: right; - color: #999; - white-space: nowrap; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-bg.jconfirm-bg-h { + opacity: 0 !important; } -/* line 41, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-guttermarker { - color: black; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-scrollpane { + -webkit-perspective: 500px; + perspective: 500px; + -webkit-perspective-origin: center; + perspective-origin: center; + display: table; + width: 100%; + height: 100%; } -/* line 42, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-guttermarker-subtle { - color: #999; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-row { + display: table-row; + width: 100%; } -/* CURSOR */ -/* line 46, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-cursor { - border-left: 1px solid black; - border-right: none; - width: 0; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-cell { + display: table-cell; + vertical-align: middle; } -/* Shown when moving in bi-directional text */ -/* line 52, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror div.CodeMirror-secondarycursor { - border-left: 1px solid silver; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-holder { + max-height: 100%; + padding: 50px 0; } -/* line 55, vendor/assets/codemirror/lib/codemirror.css */ -.cm-fat-cursor .CodeMirror-cursor { - width: auto; - border: 0 !important; - background: #7e7; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box-container { + -webkit-transition: -webkit-transform; + transition: -webkit-transform; + transition: transform; + transition: transform, -webkit-transform; + transition: transform,-webkit-transform; } -/* line 60, vendor/assets/codemirror/lib/codemirror.css */ -.cm-fat-cursor div.CodeMirror-cursors { - z-index: 1; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box-container.jconfirm-no-transition { + -webkit-transition: none !important; + transition: none !important; } -/* line 63, vendor/assets/codemirror/lib/codemirror.css */ -.cm-fat-cursor-mark { - background-color: rgba(20, 255, 20, 0.5); - -webkit-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box { + background: white; + border-radius: 4px; + position: relative; + outline: 0; + padding: 15px 15px 0; + overflow: hidden; + margin-left: auto; + margin-right: auto; } -/* line 69, vendor/assets/codemirror/lib/codemirror.css */ -.cm-animate-fat-cursor { - width: auto; - border: 0; - -webkit-animation: blink 1.06s steps(1) infinite; - animation: blink 1.06s steps(1) infinite; - background-color: #7e7; +@-webkit-keyframes type-blue { + 1%, 100% { + border-color: #3498db; + } + 50% { + border-color: #5faee3; + } } -@-webkit-keyframes blink { - 0% { +@keyframes type-blue { + 1%, 100% { + border-color: #3498db; } 50% { - background-color: transparent; - } - 100% { + border-color: #5faee3; } } -@keyframes blink { - 0% { +@-webkit-keyframes type-green { + 1%, 100% { + border-color: #2ecc71; } 50% { - background-color: transparent; - } - 100% { + border-color: #54d98c; } } -/* Can style cursor different in overwrite (non-insert) mode */ -/* line 96, vendor/assets/codemirror/lib/codemirror.css */ -.cm-tab { - display: inline-block; - text-decoration: inherit; +@keyframes type-green { + 1%, 100% { + border-color: #2ecc71; + } + 50% { + border-color: #54d98c; + } } -/* line 98, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-rulers { - position: absolute; - left: 0; - right: 0; - top: -50px; - bottom: 0; - overflow: hidden; +@-webkit-keyframes type-red { + 1%, 100% { + border-color: #e74c3c; + } + 50% { + border-color: #ed7669; + } } -/* line 103, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-ruler { - border-left: 1px solid #ccc; - top: 0; - bottom: 0; - position: absolute; +@keyframes type-red { + 1%, 100% { + border-color: #e74c3c; + } + 50% { + border-color: #ed7669; + } } -/* DEFAULT THEME */ -/* line 111, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-header { - color: blue; +@-webkit-keyframes type-orange { + 1%, 100% { + border-color: #f1c40f; + } + 50% { + border-color: #f4d03f; + } } -/* line 112, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-quote { - color: #090; +@keyframes type-orange { + 1%, 100% { + border-color: #f1c40f; + } + 50% { + border-color: #f4d03f; + } } -/* line 113, vendor/assets/codemirror/lib/codemirror.css */ -.cm-negative { - color: #d44; +@-webkit-keyframes type-purple { + 1%, 100% { + border-color: #9b59b6; + } + 50% { + border-color: #b07cc6; + } } -/* line 114, vendor/assets/codemirror/lib/codemirror.css */ -.cm-positive { - color: #292; +@keyframes type-purple { + 1%, 100% { + border-color: #9b59b6; + } + 50% { + border-color: #b07cc6; + } } -/* line 115, vendor/assets/codemirror/lib/codemirror.css */ -.cm-header, .cm-strong { - font-weight: bold; +@-webkit-keyframes type-dark { + 1%, 100% { + border-color: #34495e; + } + 50% { + border-color: #46627f; + } } -/* line 116, vendor/assets/codemirror/lib/codemirror.css */ -.cm-em { - font-style: italic; +@keyframes type-dark { + 1%, 100% { + border-color: #34495e; + } + 50% { + border-color: #46627f; + } } -/* line 117, vendor/assets/codemirror/lib/codemirror.css */ -.cm-link { - text-decoration: underline; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-animated { + -webkit-animation-duration: 2s; + animation-duration: 2s; + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; } -/* line 118, vendor/assets/codemirror/lib/codemirror.css */ -.cm-strikethrough { - text-decoration: line-through; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-blue { + border-top: solid 7px #3498db; + -webkit-animation-name: type-blue; + animation-name: type-blue; } -/* line 120, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-keyword { - color: #708; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-green { + border-top: solid 7px #2ecc71; + -webkit-animation-name: type-green; + animation-name: type-green; } -/* line 121, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-atom { - color: #219; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-red { + border-top: solid 7px #e74c3c; + -webkit-animation-name: type-red; + animation-name: type-red; } -/* line 122, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-number { - color: #164; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-orange { + border-top: solid 7px #f1c40f; + -webkit-animation-name: type-orange; + animation-name: type-orange; } -/* line 123, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-def { - color: #00f; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-purple { + border-top: solid 7px #9b59b6; + -webkit-animation-name: type-purple; + animation-name: type-purple; } -/* line 128, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-variable-2 { - color: #05a; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-dark { + border-top: solid 7px #34495e; + -webkit-animation-name: type-dark; + animation-name: type-dark; } -/* line 129, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-variable-3, .cm-s-default .cm-type { - color: #085; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.loading { + height: 120px; } -/* line 130, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-comment { - color: #a50; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.loading:before { + content: ''; + position: absolute; + left: 0; + background: white; + right: 0; + top: 0; + bottom: 0; + border-radius: 10px; + z-index: 1; } -/* line 131, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-string { - color: #a11; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.loading:after { + opacity: .6; + content: ''; + height: 30px; + width: 30px; + border: solid 3px transparent; + position: absolute; + left: 50%; + margin-left: -15px; + border-radius: 50%; + -webkit-animation: jconfirm-spin 1s infinite linear; + animation: jconfirm-spin 1s infinite linear; + border-bottom-color: dodgerblue; + top: 50%; + margin-top: -15px; + z-index: 2; } -/* line 132, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-string-2 { - color: #f50; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon { + height: 20px; + width: 20px; + position: absolute; + top: 10px; + right: 10px; + cursor: pointer; + opacity: .6; + text-align: center; + font-size: 27px !important; + line-height: 14px !important; + display: none; + z-index: 1; } -/* line 133, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-meta { - color: #555; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon:empty { + display: none; } -/* line 134, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-qualifier { - color: #555; +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon .fa { + font-size: 16px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon .glyphicon { + font-size: 16px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon .zmdi { + font-size: 16px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-closeIcon:hover { + opacity: 1; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c { + display: block; + font-size: 22px; + line-height: 20px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: default; + padding-bottom: 15px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c.jconfirm-hand { + cursor: move; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { + font-size: inherit; + display: inline-block; + vertical-align: middle; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c i { + vertical-align: middle; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c:empty { + display: none; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + font-size: inherit; + font-family: inherit; + display: inline-block; + vertical-align: middle; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-title-c .jconfirm-title:empty { + display: none; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane { + margin-bottom: 15px; + height: auto; + -webkit-transition: height .4s ease-in; + transition: height .4s ease-in; + display: inline-block; + width: 100%; + position: relative; + overflow-x: hidden; + overflow-y: auto; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane.no-scroll { + overflow-y: hidden; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar { + width: 3px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane::-webkit-scrollbar-thumb { + background: #666; + border-radius: 3px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content { + overflow: auto; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content img { + max-width: 100%; + height: auto; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box div.jconfirm-content-pane .jconfirm-content:empty { + display: none; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons { + padding-bottom: 11px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons > button { + margin-bottom: 4px; + margin-left: 2px; + margin-right: 2px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button { + display: inline-block; + padding: 6px 12px; + font-size: 14px; + font-weight: 400; + line-height: 1.42857143; + text-align: center; + white-space: nowrap; + vertical-align: middle; + touch-action: manipulation; + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + border-radius: 4px; + min-height: 1em; + -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,background .1s ease,-webkit-box-shadow .1s ease; + -webkit-transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease; + transition: opacity .1s ease,background-color .1s ease,color .1s ease,box-shadow .1s ease,background .1s ease; + -webkit-tap-highlight-color: transparent; + border: 0; + background-image: none; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue { + background-color: #3498db; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-blue:hover { + background-color: #2980b9; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green { + background-color: #2ecc71; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-green:hover { + background-color: #27ae60; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red { + background-color: #e74c3c; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-red:hover { + background-color: #c0392b; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange { + background-color: #f1c40f; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-orange:hover { + background-color: #f39c12; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default { + background-color: #ecf0f1; + color: #000; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-default:hover { + background-color: #bdc3c7; + color: #000; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple { + background-color: #9b59b6; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-purple:hover { + background-color: #8e44ad; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark { + background-color: #34495e; + color: #FFF; + text-shadow: none; + -webkit-transition: background .2s; + transition: background .2s; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box .jconfirm-buttons button.btn-dark:hover { + background-color: #2c3e50; + color: #FFF; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-red .jconfirm-title-c .jconfirm-icon-c { + color: #e74c3c !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-blue .jconfirm-title-c .jconfirm-icon-c { + color: #3498db !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-green .jconfirm-title-c .jconfirm-icon-c { + color: #2ecc71 !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-purple .jconfirm-title-c .jconfirm-icon-c { + color: #9b59b6 !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-orange .jconfirm-title-c .jconfirm-icon-c { + color: #f1c40f !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-type-dark .jconfirm-title-c .jconfirm-icon-c { + color: #34495e !important; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-clear { + clear: both; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-rtl { + direction: rtl; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-rtl div.jconfirm-closeIcon { + left: 5px; + right: auto; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-bg, .jconfirm.jconfirm-light .jconfirm-bg { + background-color: #444; + opacity: .2; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box, .jconfirm.jconfirm-light .jconfirm-box { + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + border-radius: 5px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, .jconfirm.jconfirm-light .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { + margin-right: 8px; + margin-left: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons, .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons { + float: right; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button, .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button { + text-transform: uppercase; + font-size: 14px; + font-weight: bold; + text-shadow: none; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default, .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default { + box-shadow: none; + color: #333; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white .jconfirm-box .jconfirm-buttons button.btn-default:hover, .jconfirm.jconfirm-light .jconfirm-box .jconfirm-buttons button.btn-default:hover { + background: #ddd; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-white.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, .jconfirm.jconfirm-light.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { + margin-left: 8px; + margin-right: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-bg, .jconfirm.jconfirm-dark .jconfirm-bg { + background-color: darkslategray; + opacity: .4; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box, .jconfirm.jconfirm-dark .jconfirm-box { + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2); + background: #444; + border-radius: 5px; + color: white; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box .jconfirm-title-c .jconfirm-icon-c, .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { + margin-right: 8px; + margin-left: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons, .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons { + float: right; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button, .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button { + border: 0; + background-image: none; + text-transform: uppercase; + font-size: 14px; + font-weight: bold; + text-shadow: none; + -webkit-transition: background .1s; + transition: background .1s; + color: white; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default, .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default { + box-shadow: none; + color: #fff; + background: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black .jconfirm-box .jconfirm-buttons button.btn-default:hover, .jconfirm.jconfirm-dark .jconfirm-box .jconfirm-buttons button.btn-default:hover { + background: #666; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-black.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c, .jconfirm.jconfirm-dark.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { + margin-left: 8px; + margin-right: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.hilight.jconfirm-hilight-shake { + -webkit-animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + animation: shake 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.hilight.jconfirm-hilight-glow { + -webkit-animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + animation: glow 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +@-webkit-keyframes shake { + 10%, 90% { + -webkit-transform: translate3d(-2px, 0, 0); + transform: translate3d(-2px, 0, 0); + } + 20%, 80% { + -webkit-transform: translate3d(4px, 0, 0); + transform: translate3d(4px, 0, 0); + } + 30%, 50%, 70% { + -webkit-transform: translate3d(-8px, 0, 0); + transform: translate3d(-8px, 0, 0); + } + 40%, 60% { + -webkit-transform: translate3d(8px, 0, 0); + transform: translate3d(8px, 0, 0); + } +} + +@keyframes shake { + 10%, 90% { + -webkit-transform: translate3d(-2px, 0, 0); + transform: translate3d(-2px, 0, 0); + } + 20%, 80% { + -webkit-transform: translate3d(4px, 0, 0); + transform: translate3d(4px, 0, 0); + } + 30%, 50%, 70% { + -webkit-transform: translate3d(-8px, 0, 0); + transform: translate3d(-8px, 0, 0); + } + 40%, 60% { + -webkit-transform: translate3d(8px, 0, 0); + transform: translate3d(8px, 0, 0); + } +} + +@-webkit-keyframes glow { + 0%, 100% { + box-shadow: 0 0 0 red; + } + 50% { + box-shadow: 0 0 30px red; + } +} + +@keyframes glow { + 0%, 100% { + box-shadow: 0 0 0 red; + } + 50% { + box-shadow: 0 0 30px red; + } +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm { + -webkit-perspective: 400px; + perspective: 400px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box { + opacity: 1; + -webkit-transition-property: all; + transition-property: all; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-top, .jconfirm .jconfirm-box.jconfirm-animation-left, .jconfirm .jconfirm-box.jconfirm-animation-right, .jconfirm .jconfirm-box.jconfirm-animation-bottom, .jconfirm .jconfirm-box.jconfirm-animation-opacity, .jconfirm .jconfirm-box.jconfirm-animation-zoom, .jconfirm .jconfirm-box.jconfirm-animation-scale, .jconfirm .jconfirm-box.jconfirm-animation-none, .jconfirm .jconfirm-box.jconfirm-animation-rotate, .jconfirm .jconfirm-box.jconfirm-animation-rotatex, .jconfirm .jconfirm-box.jconfirm-animation-rotatey, .jconfirm .jconfirm-box.jconfirm-animation-scaley, .jconfirm .jconfirm-box.jconfirm-animation-scalex { + opacity: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-rotate { + -webkit-transform: rotate(90deg); + transform: rotate(90deg); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-rotatex { + -webkit-transform: rotateX(90deg); + transform: rotateX(90deg); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-rotatexr { + -webkit-transform: rotateX(-90deg); + transform: rotateX(-90deg); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-rotatey { + -webkit-transform: rotatey(90deg); + transform: rotatey(90deg); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-rotateyr { + -webkit-transform: rotatey(-90deg); + transform: rotatey(-90deg); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-scaley { + -webkit-transform: scaley(1.5); + transform: scaley(1.5); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-scalex { + -webkit-transform: scalex(1.5); + transform: scalex(1.5); + -webkit-transform-origin: center; + transform-origin: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-top { + -webkit-transform: translate(0px, -100px); + transform: translate(0px, -100px); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-left { + -webkit-transform: translate(-100px, 0px); + transform: translate(-100px, 0px); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-right { + -webkit-transform: translate(100px, 0px); + transform: translate(100px, 0px); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-bottom { + -webkit-transform: translate(0px, 100px); + transform: translate(0px, 100px); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-zoom { + -webkit-transform: scale(1.2); + transform: scale(1.2); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-scale { + -webkit-transform: scale(0.5); + transform: scale(0.5); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm .jconfirm-box.jconfirm-animation-none { + visibility: hidden; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-bg { + background-color: rgba(54, 70, 93, 0.95); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box { + background-color: transparent; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-blue { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-green { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-red { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-orange { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-purple { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box.jconfirm-type-dark { + border: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-closeIcon { + color: white; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c { + text-align: center; + color: white; + font-size: 28px; + font-weight: normal; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c > * { + padding-bottom: 25px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { + margin-right: 8px; + margin-left: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content-pane { + margin-bottom: 25px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box div.jconfirm-content { + text-align: center; + color: white; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons { + text-align: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan .jconfirm-box .jconfirm-buttons button { + font-size: 16px; + border-radius: 2px; + background: #303f53; + text-shadow: none; + border: 0; + color: white; + padding: 10px; + min-width: 100px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-supervan.jconfirm-rtl .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { + margin-left: 8px; + margin-right: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-bg { + background-color: rgba(0, 0, 0, 0.67); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box { + background-color: white; + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); + padding: 30px 25px 10px 25px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { + margin-right: 8px; + margin-left: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-closeIcon { + color: rgba(0, 0, 0, 0.87); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-title-c { + color: rgba(0, 0, 0, 0.87); + font-size: 22px; + font-weight: bold; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box div.jconfirm-content { + color: rgba(0, 0, 0, 0.87); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons { + text-align: right; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material .jconfirm-box .jconfirm-buttons button { + text-transform: uppercase; + font-weight: 500; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-material.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { + margin-left: 8px; + margin-right: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-bg { + background-color: rgba(0, 0, 0, 0.21); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box { + background-color: white; + box-shadow: 0 3px 8px 0 rgba(0, 0, 0, 0.2); + border: solid 1px rgba(0, 0, 0, 0.4); + padding: 15px 0 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { + margin-right: 8px; + margin-left: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-closeIcon { + color: rgba(0, 0, 0, 0.87); +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-title-c { + color: rgba(0, 0, 0, 0.87); + font-size: 22px; + font-weight: bold; + padding-left: 15px; + padding-right: 15px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box div.jconfirm-content { + color: rgba(0, 0, 0, 0.87); + padding: 0 15px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons { + text-align: right; + padding: 10px; + margin: -5px 0 0; + border-top: solid 1px #ddd; + overflow: hidden; + border-radius: 0 0 4px 4px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap .jconfirm-box .jconfirm-buttons button { + font-weight: 500; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-bootstrap.jconfirm-rtl .jconfirm-title-c .jconfirm-icon-c { + margin-left: 8px; + margin-right: 0; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-bg { + background-color: slategray; + opacity: .6; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box { + background-color: white; + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), 0 13px 19px 2px rgba(0, 0, 0, 0.14), 0 5px 24px 4px rgba(0, 0, 0, 0.12); + padding: 30px 30px 15px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-closeIcon { + color: rgba(0, 0, 0, 0.87); + top: 15px; + right: 15px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c { + color: rgba(0, 0, 0, 0.87); + font-size: 24px; + font-weight: bold; + text-align: center; + margin-bottom: 10px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-title-c .jconfirm-icon-c { + -webkit-transition: -webkit-transform .5s; + transition: -webkit-transform .5s; + transition: transform .5s; + transition: transform .5s, -webkit-transform .5s; + transition: transform .5s,-webkit-transform .5s; + -webkit-transform: scale(0); + transform: scale(0); + display: block; + margin-right: 0; + margin-left: 0; + margin-bottom: 10px; + font-size: 69px; + color: #aaa; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box div.jconfirm-content { + text-align: center; + font-size: 15px; + color: #777; + margin-bottom: 25px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons { + text-align: center; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button { + font-weight: bold; + text-transform: uppercase; + -webkit-transition: background .1s; + transition: background .1s; + padding: 10px 20px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern .jconfirm-box .jconfirm-buttons button + button { + margin-left: 4px; +} + +/* line 9, app/assets/stylesheets/jquery-confirm.min.css */ +.jconfirm.jconfirm-modern.jconfirm-open .jconfirm-box .jconfirm-title-c .jconfirm-icon-c { + -webkit-transform: scale(1); + transform: scale(1); +} + +/* BASICS */ +/* line 3, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror { + /* Set height, width, borders, and global font properties here */ + font-family: monospace; + height: 300px; + color: black; + direction: ltr; +} + +/* PADDING */ +/* line 13, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-lines { + padding: 4px 0; + /* Vertical padding around content */ +} + +/* line 16, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + padding: 0 4px; + /* Horizontal padding of content */ +} + +/* line 21, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + background-color: white; + /* The little square between H and V scrollbars */ +} + +/* GUTTER */ +/* line 27, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutters { + border-right: 1px solid #ddd; + background-color: #f7f7f7; + white-space: nowrap; +} + +/* line 33, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-linenumber { + padding: 0 3px 0 5px; + min-width: 20px; + text-align: right; + color: #999; + white-space: nowrap; +} + +/* line 41, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-guttermarker { + color: black; +} + +/* line 42, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-guttermarker-subtle { + color: #999; +} + +/* CURSOR */ +/* line 46, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-cursor { + border-left: 1px solid black; + border-right: none; + width: 0; +} + +/* Shown when moving in bi-directional text */ +/* line 52, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror div.CodeMirror-secondarycursor { + border-left: 1px solid silver; +} + +/* line 55, vendor/assets/codemirror/lib/codemirror.css */ +.cm-fat-cursor .CodeMirror-cursor { + width: auto; + border: 0 !important; + background: #7e7; +} + +/* line 60, vendor/assets/codemirror/lib/codemirror.css */ +.cm-fat-cursor div.CodeMirror-cursors { + z-index: 1; +} + +/* line 63, vendor/assets/codemirror/lib/codemirror.css */ +.cm-fat-cursor-mark { + background-color: rgba(20, 255, 20, 0.5); + -webkit-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; +} + +/* line 69, vendor/assets/codemirror/lib/codemirror.css */ +.cm-animate-fat-cursor { + width: auto; + border: 0; + -webkit-animation: blink 1.06s steps(1) infinite; + animation: blink 1.06s steps(1) infinite; + background-color: #7e7; +} + +@-webkit-keyframes blink { + 0% { + } + 50% { + background-color: transparent; + } + 100% { + } +} + +@keyframes blink { + 0% { + } + 50% { + background-color: transparent; + } + 100% { + } +} + +/* Can style cursor different in overwrite (non-insert) mode */ +/* line 96, vendor/assets/codemirror/lib/codemirror.css */ +.cm-tab { + display: inline-block; + text-decoration: inherit; +} + +/* line 98, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-rulers { + position: absolute; + left: 0; + right: 0; + top: -50px; + bottom: 0; + overflow: hidden; +} + +/* line 103, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-ruler { + border-left: 1px solid #ccc; + top: 0; + bottom: 0; + position: absolute; +} + +/* DEFAULT THEME */ +/* line 111, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-header { + color: blue; +} + +/* line 112, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-quote { + color: #090; +} + +/* line 113, vendor/assets/codemirror/lib/codemirror.css */ +.cm-negative { + color: #d44; +} + +/* line 114, vendor/assets/codemirror/lib/codemirror.css */ +.cm-positive { + color: #292; +} + +/* line 115, vendor/assets/codemirror/lib/codemirror.css */ +.cm-header, .cm-strong { + font-weight: bold; +} + +/* line 116, vendor/assets/codemirror/lib/codemirror.css */ +.cm-em { + font-style: italic; +} + +/* line 117, vendor/assets/codemirror/lib/codemirror.css */ +.cm-link { + text-decoration: underline; +} + +/* line 118, vendor/assets/codemirror/lib/codemirror.css */ +.cm-strikethrough { + text-decoration: line-through; +} + +/* line 120, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-keyword { + color: #708; +} + +/* line 121, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-atom { + color: #219; +} + +/* line 122, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-number { + color: #164; +} + +/* line 123, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-def { + color: #00f; +} + +/* line 128, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-variable-2 { + color: #05a; +} + +/* line 129, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-variable-3, .cm-s-default .cm-type { + color: #085; +} + +/* line 130, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-comment { + color: #a50; +} + +/* line 131, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-string { + color: #a11; +} + +/* line 132, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-string-2 { + color: #f50; +} + +/* line 133, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-meta { + color: #555; +} + +/* line 134, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-qualifier { + color: #555; } /* line 135, vendor/assets/codemirror/lib/codemirror.css */ @@ -18181,360 +19406,5336 @@ form.was-validated select:valid ~ .select2-container--bootstrap4 .select2-select color: #30a; } -/* line 136, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-bracket { - color: #997; +/* line 136, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-bracket { + color: #997; +} + +/* line 137, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-tag { + color: #170; +} + +/* line 138, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-attribute { + color: #00c; +} + +/* line 139, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-hr { + color: #999; +} + +/* line 140, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-link { + color: #00c; +} + +/* line 142, vendor/assets/codemirror/lib/codemirror.css */ +.cm-s-default .cm-error { + color: #f00; +} + +/* line 143, vendor/assets/codemirror/lib/codemirror.css */ +.cm-invalidchar { + color: #f00; +} + +/* line 145, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-composing { + border-bottom: 2px solid; +} + +/* Default styles for common addons */ +/* line 149, vendor/assets/codemirror/lib/codemirror.css */ +div.CodeMirror span.CodeMirror-matchingbracket { + color: #0b0; +} + +/* line 150, vendor/assets/codemirror/lib/codemirror.css */ +div.CodeMirror span.CodeMirror-nonmatchingbracket { + color: #a22; +} + +/* line 151, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-matchingtag { + background: rgba(255, 150, 0, 0.3); +} + +/* line 152, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-activeline-background { + background: #e8f2ff; +} + +/* STOP */ +/* The rest of this file contains styles related to the mechanics of + the editor. You probably shouldn't touch them. */ +/* line 159, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror { + position: relative; + overflow: hidden; + background: white; +} + +/* line 165, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-scroll { + overflow: scroll !important; + /* Things will break if this is overridden */ + /* 30px is the magic margin used to hide the element's real scrollbars */ + /* See overflow: hidden in .CodeMirror */ + margin-bottom: -30px; + margin-right: -30px; + padding-bottom: 30px; + height: 100%; + outline: none; + /* Prevent dragging from highlighting the element */ + position: relative; +} + +/* line 175, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-sizer { + position: relative; + border-right: 30px solid transparent; +} + +/* The fake, visible scrollbars. Used to force redraw during scrolling + before actual scrolling happens, thus preventing shaking and + flickering artifacts. */ +/* line 183, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { + position: absolute; + z-index: 6; + display: none; +} + +/* line 188, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-vscrollbar { + right: 0; + top: 0; + overflow-x: hidden; + overflow-y: scroll; +} + +/* line 193, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-hscrollbar { + bottom: 0; + left: 0; + overflow-y: hidden; + overflow-x: scroll; +} + +/* line 198, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-scrollbar-filler { + right: 0; + bottom: 0; +} + +/* line 201, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-filler { + left: 0; + bottom: 0; +} + +/* line 205, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutters { + position: absolute; + left: 0; + top: 0; + min-height: 100%; + z-index: 3; +} + +/* line 210, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter { + white-space: normal; + height: 100%; + display: inline-block; + vertical-align: top; + margin-bottom: -30px; +} + +/* line 217, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-wrapper { + position: absolute; + z-index: 4; + background: none !important; + border: none !important; +} + +/* line 223, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-background { + position: absolute; + top: 0; + bottom: 0; + z-index: 4; +} + +/* line 228, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-elt { + position: absolute; + cursor: default; + z-index: 4; +} + +/* line 233, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-wrapper ::-moz-selection { + background-color: transparent; +} +.CodeMirror-gutter-wrapper ::selection { + background-color: transparent; +} + +/* line 234, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-gutter-wrapper ::-moz-selection { + background-color: transparent; +} + +/* line 236, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-lines { + cursor: text; + min-height: 1px; + /* prevents collapsing before first draw */ +} + +/* line 240, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror pre.CodeMirror-line, +.CodeMirror pre.CodeMirror-line-like { + /* Reset some styles that the rest of the page might have set */ + border-radius: 0; + border-width: 0; + background: transparent; + font-family: inherit; + font-size: inherit; + margin: 0; + white-space: pre; + word-wrap: normal; + line-height: inherit; + color: inherit; + z-index: 2; + position: relative; + overflow: visible; + -webkit-tap-highlight-color: transparent; + -webkit-font-variant-ligatures: contextual; + font-variant-ligatures: contextual; +} + +/* line 260, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-wrap pre.CodeMirror-line, +.CodeMirror-wrap pre.CodeMirror-line-like { + word-wrap: break-word; + white-space: pre-wrap; + word-break: normal; +} + +/* line 267, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-linebackground { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + z-index: 0; +} + +/* line 273, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-linewidget { + position: relative; + z-index: 2; + padding: 0.1px; + /* Force widget margins to stay inside of the container */ +} + +/* line 281, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-rtl pre { + direction: rtl; +} + +/* line 283, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-code { + outline: none; +} + +/* Force content-box sizing for the elements where we expect it */ +/* line 288, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-scroll, +.CodeMirror-sizer, +.CodeMirror-gutter, +.CodeMirror-gutters, +.CodeMirror-linenumber { + box-sizing: content-box; +} + +/* line 297, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-measure { + position: absolute; + width: 100%; + height: 0; + overflow: hidden; + visibility: hidden; +} + +/* line 305, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-cursor { + position: absolute; + pointer-events: none; +} + +/* line 309, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-measure pre { + position: static; +} + +/* line 311, vendor/assets/codemirror/lib/codemirror.css */ +div.CodeMirror-cursors { + visibility: hidden; + position: relative; + z-index: 3; +} + +/* line 316, vendor/assets/codemirror/lib/codemirror.css */ +div.CodeMirror-dragcursors { + visibility: visible; +} + +/* line 320, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-focused div.CodeMirror-cursors { + visibility: visible; +} + +/* line 324, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-selected { + background: #d9d9d9; +} + +/* line 325, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-focused .CodeMirror-selected { + background: #d7d4f0; +} + +/* line 326, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-crosshair { + cursor: crosshair; +} + +/* line 327, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { + background: #d7d4f0; +} +.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { + background: #d7d4f0; +} + +/* line 328, vendor/assets/codemirror/lib/codemirror.css */ +.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { + background: #d7d4f0; +} + +/* line 330, vendor/assets/codemirror/lib/codemirror.css */ +.cm-searching { + background-color: #ffa; + background-color: rgba(255, 255, 0, 0.4); +} + +/* Used to force a border model for a node */ +/* line 336, vendor/assets/codemirror/lib/codemirror.css */ +.cm-force-border { + padding-right: .1px; +} + +@media print { + /* Hide the cursor when printing */ + /* line 340, vendor/assets/codemirror/lib/codemirror.css */ + .CodeMirror div.CodeMirror-cursors { + visibility: hidden; + } +} + +/* See issue #2901 */ +/* line 346, vendor/assets/codemirror/lib/codemirror.css */ +.cm-tab-wrap-hack:after { + content: ''; +} + +/* Help users use markselection to safely style text background */ +/* line 349, vendor/assets/codemirror/lib/codemirror.css */ +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 137, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-tag { - color: #170; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +li.L1, li.L3, li.L5, li.L7, li.L9 { + background: #eee; } -/* line 138, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-attribute { - color: #00c; +/* 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 139, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-hr { +/* 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 140, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-link { - color: #00c; +/* 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 142, vendor/assets/codemirror/lib/codemirror.css */ -.cm-s-default .cm-error { - color: #f00; +/* 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 143, vendor/assets/codemirror/lib/codemirror.css */ -.cm-invalidchar { - color: #f00; +/* 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 145, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-composing { - border-bottom: 2px solid; +/* 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; } -/* Default styles for common addons */ -/* line 149, vendor/assets/codemirror/lib/codemirror.css */ -div.CodeMirror span.CodeMirror-matchingbracket { - color: #0b0; +/* 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 150, vendor/assets/codemirror/lib/codemirror.css */ -div.CodeMirror span.CodeMirror-nonmatchingbracket { - color: #a22; +/* 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 151, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-matchingtag { - background: rgba(255, 150, 0, 0.3); +/* 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 152, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-activeline-background { - background: #e8f2ff; +/* 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; } -/* STOP */ -/* The rest of this file contains styles related to the mechanics of - the editor. You probably shouldn't touch them. */ -/* line 159, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror { +/* 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; - overflow: hidden; - background: white; } -/* line 165, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-scroll { - overflow: scroll !important; - /* Things will break if this is overridden */ - /* 30px is the magic margin used to hide the element's real scrollbars */ - /* See overflow: hidden in .CodeMirror */ - margin-bottom: -30px; - margin-right: -30px; - padding-bottom: 30px; - height: 100%; - outline: none; - /* Prevent dragging from highlighting the element */ - 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 175, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-sizer { - position: relative; - border-right: 30px solid transparent; +/* 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; } -/* The fake, visible scrollbars. Used to force redraw during scrolling - before actual scrolling happens, thus preventing shaking and - flickering artifacts. */ -/* line 183, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { - position: absolute; - z-index: 6; - display: none; +/* 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 188, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-vscrollbar { - right: 0; - top: 0; - overflow-x: hidden; - overflow-y: scroll; +/* 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 193, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-hscrollbar { - bottom: 0; - left: 0; - overflow-y: hidden; - overflow-x: scroll; +/* 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 198, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-scrollbar-filler { - right: 0; - bottom: 0; +/* 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 201, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-filler { - left: 0; - bottom: 0; +/* 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 205, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutters { - position: absolute; - left: 0; - top: 0; - min-height: 100%; - z-index: 3; +/* 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 210, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter { - white-space: normal; - height: 100%; +/* 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; - vertical-align: top; - margin-bottom: -30px; + -webkit-transition: background-color 500ms ease-out; + transition: background-color 500ms ease-out; } -/* line 217, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-wrapper { - position: absolute; - z-index: 4; - background: none !important; - border: none !important; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-html-preview textarea, .editormd-onlyread .editormd-toolbar { + display: none; } -/* line 223, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-background { - position: absolute; - top: 0; - bottom: 0; - z-index: 4; +/* 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 228, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-elt { +/* 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; - cursor: default; - z-index: 4; + top: 25px; + right: 35px; + z-index: 19; + -webkit-transition: background-color 300ms ease-out; + transition: background-color 300ms ease-out; } -/* line 233, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-wrapper ::-moz-selection { - background-color: transparent; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-close-btn:hover { + background-color: #999; } -.CodeMirror-gutter-wrapper ::selection { - background-color: transparent; + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-active { + width: 100%; + padding: 40px; } -/* line 234, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-gutter-wrapper ::-moz-selection { - background-color: transparent; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark { + color: #777; + background: #2C2827; } -/* line 236, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-lines { - cursor: text; - min-height: 1px; - /* prevents collapsing before first draw */ +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container { + color: #888; + background-color: #2C2827; } -/* line 240, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror pre.CodeMirror-line, -.CodeMirror pre.CodeMirror-line-like { - /* Reset some styles that the rest of the page might have set */ - border-radius: 0; - border-width: 0; - background: transparent; - font-family: inherit; - font-size: inherit; - margin: 0; - white-space: pre; - word-wrap: normal; - line-height: inherit; - color: inherit; - z-index: 2; - position: relative; - overflow: visible; - -webkit-tap-highlight-color: transparent; - -webkit-font-variant-ligatures: contextual; - font-variant-ligatures: contextual; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .editormd-preview-container pre.prettyprint { + border: none; } -/* line 260, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-wrap pre.CodeMirror-line, -.CodeMirror-wrap pre.CodeMirror-line-like { - word-wrap: break-word; - white-space: pre-wrap; - word-break: normal; +/* 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 267, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-linebackground { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 0; +/* 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 273, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-linewidget { - position: relative; - z-index: 2; - padding: 0.1px; - /* Force widget margins to stay inside of the container */ +/* 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 281, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-rtl pre { - direction: rtl; +/* 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 283, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-code { - outline: none; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark [class*=editormd-logo] { + color: #2196F3; } -/* Force content-box sizing for the elements where we expect it */ -/* line 288, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-scroll, -.CodeMirror-sizer, -.CodeMirror-gutter, -.CodeMirror-gutters, -.CodeMirror-linenumber { - box-sizing: content-box; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .sequence-diagram text { + fill: #fff; } -/* line 297, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-measure { - position: absolute; - width: 100%; - height: 0; - overflow: hidden; - visibility: hidden; +/* 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 305, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-cursor { - position: absolute; - pointer-events: none; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart path, .editormd-preview-theme-dark .flowchart rect { + stroke: #A6C6FF; } -/* line 309, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-measure pre { - position: static; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart rect { + fill: #A6C6FF; } -/* line 311, vendor/assets/codemirror/lib/codemirror.css */ -div.CodeMirror-cursors { - visibility: hidden; - position: relative; - z-index: 3; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-preview-theme-dark .flowchart text { + fill: #5879B4; } -/* line 316, vendor/assets/codemirror/lib/codemirror.css */ -div.CodeMirror-dragcursors { - visibility: visible; +@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 320, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-focused div.CodeMirror-cursors { - visibility: visible; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-onlyread .CodeMirror { + margin-top: 0; } -/* line 324, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-selected { - background: #d9d9d9; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-onlyread .editormd-preview { + top: 0; } -/* line 325, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-focused .CodeMirror-selected { - background: #d7d4f0; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-fullscreen { + position: fixed; + top: 0; + left: 0; + border: none; + margin: 0 auto; } -/* line 326, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-crosshair { - cursor: crosshair; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark { + border-color: #1a1a17; } -/* line 327, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { - background: #d7d4f0; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-toolbar { + background: #1A1A17; + border-color: #1a1a17; } -.CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { - background: #d7d4f0; + +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-menu > li > a { + color: #777; + border-color: #1a1a17; } -/* line 328, vendor/assets/codemirror/lib/codemirror.css */ -.CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { - background: #d7d4f0; +/* 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 330, vendor/assets/codemirror/lib/codemirror.css */ -.cm-searching { - background-color: #ffa; - background-color: rgba(255, 255, 0, 0.4); +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .editormd-menu > li.divider { + border-right: 1px solid #111; } -/* Used to force a border model for a node */ -/* line 336, vendor/assets/codemirror/lib/codemirror.css */ -.cm-force-border { - padding-right: .1px; +/* line 5, vendor/assets/editormd/css/editormd.min.css */ +.editormd-theme-dark .CodeMirror { + border-right: 1px solid rgba(0, 0, 0, 0.1); } -@media print { - /* Hide the cursor when printing */ - /* line 340, vendor/assets/codemirror/lib/codemirror.css */ - .CodeMirror div.CodeMirror-cursors { - visibility: hidden; - } +/* 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); } -/* See issue #2901 */ -/* line 346, vendor/assets/codemirror/lib/codemirror.css */ -.cm-tab-wrap-hack:after { - content: ''; +/* line 9, vendor/assets/dragula/dragula.css */ +.gu-hide { + display: none !important; } -/* Help users use markselection to safely style text background */ -/* line 349, vendor/assets/codemirror/lib/codemirror.css */ -span.CodeMirror-selectedtext { - background: none; +/* 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 */ @@ -18594,6 +24795,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 +25087,48 @@ input.form-control { border: 1px solid #ced4da; } +/* line 114, app/assets/stylesheets/admins/common.scss */ +.admin-body-container .batch-action-container { + margin-bottom: -15px; + padding: 10px 20px 0; + background: #fff; +} + +/* 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 +25164,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 +25217,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 +25729,7 @@ input.form-control { color: #6c757d; } -/* line 14, app/assets/stylesheets/admin.scss */ +/* line 18, app/assets/stylesheets/admin.scss */ body { width: 100vw; height: 100vh; @@ -19280,34 +25744,29 @@ body { overflow: hidden; } -/* line 28, app/assets/stylesheets/admin.scss */ +/* line 32, app/assets/stylesheets/admin.scss */ .simple_form .form-group .collection_radio_buttons { margin-bottom: 0px; } -/* line 32, app/assets/stylesheets/admin.scss */ +/* line 36, 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 42, app/assets/stylesheets/admin.scss */ input.form-control { font-size: 14px; } -/* line 42, app/assets/stylesheets/admin.scss */ +/* line 46, app/assets/stylesheets/admin.scss */ .btn-default { color: #666; background: #e1e1e1 !important; } -/* line 46, app/assets/stylesheets/admin.scss */ +/* line 50, 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-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css.gz b/public/assets/admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css.gz new file mode 100644 index 000000000..a19afd2c4 Binary files /dev/null and b/public/assets/admin-59c59f8cae8bef4a8359286c985458110c9d03ea121516595c988943f4717c38.css.gz differ diff --git a/public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js.gz b/public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js.gz deleted file mode 100644 index 734aac10e..000000000 Binary files a/public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js.gz and /dev/null differ diff --git a/public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js b/public/assets/admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js similarity index 93% rename from public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js rename to public/assets/admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js index 61e3d71b7..ce87b3e0e 100644 --- a/public/assets/admin-73c70ed3ded5da876bc29f9fb1ec5f7d561b068730a3a8ead9b3e6acc63ca674.js +++ b/public/assets/admin-c9e5ebe6191548550e27514196ea125cfbb402820ec125a0c9acf99d2d378fe4.js @@ -27816,6 +27816,85 @@ $.fn.bootstrapViewer.defaults = { }); } })); +/*! + * jquery-confirm v3.3.4 (http://craftpip.github.io/jquery-confirm/) + * Author: Boniface Pereira + * Website: www.craftpip.com + * Contact: hey@craftpip.com + * + * Copyright 2013-2019 jquery-confirm + * Licensed under MIT (https://github.com/craftpip/jquery-confirm/blob/master/LICENSE) + */ + +(function(factory){if(typeof define==="function"&&define.amd){define(["jquery"],factory);}else{if(typeof module==="object"&&module.exports){module.exports=function(root,jQuery){if(jQuery===undefined){if(typeof window!=="undefined"){jQuery=require("jquery");}else{jQuery=require("jquery")(root);}}factory(jQuery);return jQuery;};}else{factory(jQuery);}}}(function($){var w=window;$.fn.confirm=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}$(this).each(function(){var $this=$(this);if($this.attr("jc-attached")){console.warn("jConfirm has already been attached to this element ",$this[0]);return;}$this.on("click",function(e){e.preventDefault();var jcOption=$.extend({},options);if($this.attr("data-title")){jcOption.title=$this.attr("data-title");}if($this.attr("data-content")){jcOption.content=$this.attr("data-content");}if(typeof jcOption.buttons==="undefined"){jcOption.buttons={};}jcOption["$target"]=$this;if($this.attr("href")&&Object.keys(jcOption.buttons).length===0){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];jcOption.buttons=buttons;jcOption.buttons[firstBtn].action=function(){location.href=$this.attr("href");};}jcOption.closeIcon=false;var instance=$.confirm(jcOption);});$this.attr("jc-attached",true);});return $(this);};$.confirm=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!=="object"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});options.buttons=buttons;}return w.jconfirm(options);};$.alert=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false};}var putDefaultButtons=!(options.buttons===false);if(typeof options.buttons!=="object"){options.buttons={};}if(Object.keys(options.buttons).length===0&&putDefaultButtons){var buttons=$.extend(true,{},w.jconfirm.pluginDefaults.defaultButtons,(w.jconfirm.defaults||{}).defaultButtons||{});var firstBtn=Object.keys(buttons)[0];options.buttons[firstBtn]=buttons[firstBtn];}return w.jconfirm(options);};$.dialog=function(options,option2){if(typeof options==="undefined"){options={};}if(typeof options==="string"){options={content:options,title:(option2)?option2:false,closeIcon:function(){}};}options.buttons={};if(typeof options.closeIcon==="undefined"){options.closeIcon=function(){};}options.confirmKeys=[13];return w.jconfirm(options);};w.jconfirm=function(options){if(typeof options==="undefined"){options={};}var pluginOptions=$.extend(true,{},w.jconfirm.pluginDefaults);if(w.jconfirm.defaults){pluginOptions=$.extend(true,pluginOptions,w.jconfirm.defaults);}pluginOptions=$.extend(true,{},pluginOptions,options);var instance=new w.Jconfirm(pluginOptions);w.jconfirm.instances.push(instance);return instance;};w.Jconfirm=function(options){$.extend(this,options);this._init();};w.Jconfirm.prototype={_init:function(){var that=this;if(!w.jconfirm.instances.length){w.jconfirm.lastFocused=$("body").find(":focus");}this._id=Math.round(Math.random()*99999);this.contentParsed=$(document.createElement("div"));if(!this.lazyOpen){setTimeout(function(){that.open();},0);}},_buildHTML:function(){var that=this;this._parseAnimation(this.animation,"o");this._parseAnimation(this.closeAnimation,"c");this._parseBgDismissAnimation(this.backgroundDismissAnimation);this._parseColumnClass(this.columnClass);this._parseTheme(this.theme);this._parseType(this.type);var template=$(this.template);template.find(".jconfirm-box").addClass(this.animationParsed).addClass(this.backgroundDismissAnimationParsed).addClass(this.typeParsed);if(this.typeAnimated){template.find(".jconfirm-box").addClass("jconfirm-type-animated");}if(this.useBootstrap){template.find(".jc-bs3-row").addClass(this.bootstrapClasses.row);template.find(".jc-bs3-row").addClass("justify-content-md-center justify-content-sm-center justify-content-xs-center justify-content-lg-center");template.find(".jconfirm-box-container").addClass(this.columnClassParsed);if(this.containerFluid){template.find(".jc-bs3-container").addClass(this.bootstrapClasses.containerFluid);}else{template.find(".jc-bs3-container").addClass(this.bootstrapClasses.container);}}else{template.find(".jconfirm-box").css("width",this.boxWidth);}if(this.titleClass){template.find(".jconfirm-title-c").addClass(this.titleClass);}template.addClass(this.themeParsed);var ariaLabel="jconfirm-box"+this._id;template.find(".jconfirm-box").attr("aria-labelledby",ariaLabel).attr("tabindex",-1);template.find(".jconfirm-content").attr("id",ariaLabel);if(this.bgOpacity!==null){template.find(".jconfirm-bg").css("opacity",this.bgOpacity);}if(this.rtl){template.addClass("jconfirm-rtl");}this.$el=template.appendTo(this.container);this.$jconfirmBoxContainer=this.$el.find(".jconfirm-box-container");this.$jconfirmBox=this.$body=this.$el.find(".jconfirm-box");this.$jconfirmBg=this.$el.find(".jconfirm-bg");this.$title=this.$el.find(".jconfirm-title");this.$titleContainer=this.$el.find(".jconfirm-title-c");this.$content=this.$el.find("div.jconfirm-content");this.$contentPane=this.$el.find(".jconfirm-content-pane");this.$icon=this.$el.find(".jconfirm-icon-c");this.$closeIcon=this.$el.find(".jconfirm-closeIcon");this.$holder=this.$el.find(".jconfirm-holder");this.$btnc=this.$el.find(".jconfirm-buttons");this.$scrollPane=this.$el.find(".jconfirm-scrollpane");that.setStartingPoint();this._contentReady=$.Deferred();this._modalReady=$.Deferred();this.$holder.css({"padding-top":this.offsetTop,"padding-bottom":this.offsetBottom,});this.setTitle();this.setIcon();this._setButtons();this._parseContent();this.initDraggable();if(this.isAjax){this.showLoading(false);}$.when(this._contentReady,this._modalReady).then(function(){if(that.isAjaxLoading){setTimeout(function(){that.isAjaxLoading=false;that.setContent();that.setTitle();that.setIcon();setTimeout(function(){that.hideLoading(false);that._updateContentMaxHeight();},100);if(typeof that.onContentReady==="function"){that.onContentReady();}},50);}else{that._updateContentMaxHeight();that.setTitle();that.setIcon();if(typeof that.onContentReady==="function"){that.onContentReady();}}if(that.autoClose){that._startCountDown();}}).then(function(){that._watchContent();});if(this.animation==="none"){this.animationSpeed=1;this.animationBounce=1;}this.$body.css(this._getCSS(this.animationSpeed,this.animationBounce));this.$contentPane.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBg.css(this._getCSS(this.animationSpeed,1));this.$jconfirmBoxContainer.css(this._getCSS(this.animationSpeed,1));},_typePrefix:"jconfirm-type-",typeParsed:"",_parseType:function(type){this.typeParsed=this._typePrefix+type;},setType:function(type){var oldClass=this.typeParsed;this._parseType(type);this.$jconfirmBox.removeClass(oldClass).addClass(this.typeParsed);},themeParsed:"",_themePrefix:"jconfirm-",setTheme:function(theme){var previous=this.theme;this.theme=theme||this.theme;this._parseTheme(this.theme);if(previous){this.$el.removeClass(previous);}this.$el.addClass(this.themeParsed);this.theme=theme;},_parseTheme:function(theme){var that=this;theme=theme.split(",");$.each(theme,function(k,a){if(a.indexOf(that._themePrefix)===-1){theme[k]=that._themePrefix+$.trim(a);}});this.themeParsed=theme.join(" ").toLowerCase();},backgroundDismissAnimationParsed:"",_bgDismissPrefix:"jconfirm-hilight-",_parseBgDismissAnimation:function(bgDismissAnimation){var animation=bgDismissAnimation.split(",");var that=this;$.each(animation,function(k,a){if(a.indexOf(that._bgDismissPrefix)===-1){animation[k]=that._bgDismissPrefix+$.trim(a);}});this.backgroundDismissAnimationParsed=animation.join(" ").toLowerCase();},animationParsed:"",closeAnimationParsed:"",_animationPrefix:"jconfirm-animation-",setAnimation:function(animation){this.animation=animation||this.animation;this._parseAnimation(this.animation,"o");},_parseAnimation:function(animation,which){which=which||"o";var animations=animation.split(",");var that=this;$.each(animations,function(k,a){if(a.indexOf(that._animationPrefix)===-1){animations[k]=that._animationPrefix+$.trim(a);}});var a_string=animations.join(" ").toLowerCase();if(which==="o"){this.animationParsed=a_string;}else{this.closeAnimationParsed=a_string;}return a_string;},setCloseAnimation:function(closeAnimation){this.closeAnimation=closeAnimation||this.closeAnimation;this._parseAnimation(this.closeAnimation,"c");},setAnimationSpeed:function(speed){this.animationSpeed=speed||this.animationSpeed;},columnClassParsed:"",setColumnClass:function(colClass){if(!this.useBootstrap){console.warn("cannot set columnClass, useBootstrap is set to false");return;}this.columnClass=colClass||this.columnClass;this._parseColumnClass(this.columnClass);this.$jconfirmBoxContainer.addClass(this.columnClassParsed);},_updateContentMaxHeight:function(){var height=$(window).height()-(this.$jconfirmBox.outerHeight()-this.$contentPane.outerHeight())-(this.offsetTop+this.offsetBottom);this.$contentPane.css({"max-height":height+"px"});},setBoxWidth:function(width){if(this.useBootstrap){console.warn("cannot set boxWidth, useBootstrap is set to true");return;}this.boxWidth=width;this.$jconfirmBox.css("width",width);},_parseColumnClass:function(colClass){colClass=colClass.toLowerCase();var p;switch(colClass){case"xl":case"xlarge":p="col-md-12";break;case"l":case"large":p="col-md-8 col-md-offset-2";break;case"m":case"medium":p="col-md-6 col-md-offset-3";break;case"s":case"small":p="col-md-4 col-md-offset-4";break;case"xs":case"xsmall":p="col-md-2 col-md-offset-5";break;default:p=colClass;}this.columnClassParsed=p;},initDraggable:function(){var that=this;var $t=this.$titleContainer;this.resetDrag();if(this.draggable){$t.on("mousedown",function(e){$t.addClass("jconfirm-hand");that.mouseX=e.clientX;that.mouseY=e.clientY;that.isDrag=true;});$(window).on("mousemove."+this._id,function(e){if(that.isDrag){that.movingX=e.clientX-that.mouseX+that.initialX;that.movingY=e.clientY-that.mouseY+that.initialY;that.setDrag();}});$(window).on("mouseup."+this._id,function(){$t.removeClass("jconfirm-hand");if(that.isDrag){that.isDrag=false;that.initialX=that.movingX;that.initialY=that.movingY;}});}},resetDrag:function(){this.isDrag=false;this.initialX=0;this.initialY=0;this.movingX=0;this.movingY=0;this.mouseX=0;this.mouseY=0;this.$jconfirmBoxContainer.css("transform","translate("+0+"px, "+0+"px)");},setDrag:function(){if(!this.draggable){return;}this.alignMiddle=false;var boxWidth=this.$jconfirmBox.outerWidth();var boxHeight=this.$jconfirmBox.outerHeight();var windowWidth=$(window).width();var windowHeight=$(window).height();var that=this;var dragUpdate=1;if(that.movingX%dragUpdate===0||that.movingY%dragUpdate===0){if(that.dragWindowBorder){var leftDistance=(windowWidth/2)-boxWidth/2;var topDistance=(windowHeight/2)-boxHeight/2;topDistance-=that.dragWindowGap;leftDistance-=that.dragWindowGap;if(leftDistance+that.movingX<0){that.movingX=-leftDistance;}else{if(leftDistance-that.movingX<0){that.movingX=leftDistance;}}if(topDistance+that.movingY<0){that.movingY=-topDistance;}else{if(topDistance-that.movingY<0){that.movingY=topDistance;}}}that.$jconfirmBoxContainer.css("transform","translate("+that.movingX+"px, "+that.movingY+"px)");}},_scrollTop:function(){if(typeof pageYOffset!=="undefined"){return pageYOffset;}else{var B=document.body;var D=document.documentElement;D=(D.clientHeight)?D:B;return D.scrollTop;}},_watchContent:function(){var that=this;if(this._timer){clearInterval(this._timer);}var prevContentHeight=0;this._timer=setInterval(function(){if(that.smoothContent){var contentHeight=that.$content.outerHeight()||0;if(contentHeight!==prevContentHeight){prevContentHeight=contentHeight;}var wh=$(window).height();var total=that.offsetTop+that.offsetBottom+that.$jconfirmBox.height()-that.$contentPane.height()+that.$content.height();if(total').html(that.buttons[key].text).addClass(that.buttons[key].btnClass).prop("disabled",that.buttons[key].isDisabled).css("display",that.buttons[key].isHidden?"none":"").click(function(e){e.preventDefault();var res=that.buttons[key].action.apply(that,[that.buttons[key]]);that.onAction.apply(that,[key,that.buttons[key]]);that._stopCountDown();if(typeof res==="undefined"||res){that.close();}});that.buttons[key].el=button_element;that.buttons[key].setText=function(text){button_element.html(text);};that.buttons[key].addClass=function(className){button_element.addClass(className);};that.buttons[key].removeClass=function(className){button_element.removeClass(className);};that.buttons[key].disable=function(){that.buttons[key].isDisabled=true;button_element.prop("disabled",true);};that.buttons[key].enable=function(){that.buttons[key].isDisabled=false;button_element.prop("disabled",false);};that.buttons[key].show=function(){that.buttons[key].isHidden=false;button_element.css("display","");};that.buttons[key].hide=function(){that.buttons[key].isHidden=true;button_element.css("display","none");};that["$_"+key]=that["$$"+key]=button_element;that.$btnc.append(button_element);});if(total_buttons===0){this.$btnc.hide();}if(this.closeIcon===null&&total_buttons===0){this.closeIcon=true;}if(this.closeIcon){if(this.closeIconClass){var closeHtml='';this.$closeIcon.html(closeHtml);}this.$closeIcon.click(function(e){e.preventDefault();var buttonName=false;var shouldClose=false;var str;if(typeof that.closeIcon==="function"){str=that.closeIcon();}else{str=that.closeIcon;}if(typeof str==="string"&&typeof that.buttons[str]!=="undefined"){buttonName=str;shouldClose=false;}else{if(typeof str==="undefined"||!!(str)===true){shouldClose=true;}else{shouldClose=false;}}if(buttonName){var btnResponse=that.buttons[buttonName].action.apply(that);shouldClose=(typeof btnResponse==="undefined")||!!(btnResponse);}if(shouldClose){that.close();}});this.$closeIcon.show();}else{this.$closeIcon.hide();}},setTitle:function(string,force){force=force||false;if(typeof string!=="undefined"){if(typeof string==="string"){this.title=string;}else{if(typeof string==="function"){if(typeof string.promise==="function"){console.error("Promise was returned from title function, this is not supported.");}var response=string();if(typeof response==="string"){this.title=response;}else{this.title=false;}}else{this.title=false;}}}if(this.isAjaxLoading&&!force){return;}this.$title.html(this.title||"");this.updateTitleContainer();},setIcon:function(iconClass,force){force=force||false;if(typeof iconClass!=="undefined"){if(typeof iconClass==="string"){this.icon=iconClass;}else{if(typeof iconClass==="function"){var response=iconClass();if(typeof response==="string"){this.icon=response;}else{this.icon=false;}}else{this.icon=false;}}}if(this.isAjaxLoading&&!force){return;}this.$icon.html(this.icon?'':"");this.updateTitleContainer();},updateTitleContainer:function(){if(!this.title&&!this.icon){this.$titleContainer.hide();}else{this.$titleContainer.show();}},setContentPrepend:function(content,force){if(!content){return;}this.contentParsed.prepend(content);},setContentAppend:function(content){if(!content){return;}this.contentParsed.append(content);},setContent:function(content,force){force=!!force;var that=this;if(content){this.contentParsed.html("").append(content);}if(this.isAjaxLoading&&!force){return;}this.$content.html("");this.$content.append(this.contentParsed);setTimeout(function(){that.$body.find("input[autofocus]:visible:first").focus();},100);},loadingSpinner:false,showLoading:function(disableButtons){this.loadingSpinner=true;this.$jconfirmBox.addClass("loading");if(disableButtons){this.$btnc.find("button").prop("disabled",true);}},hideLoading:function(enableButtons){this.loadingSpinner=false;this.$jconfirmBox.removeClass("loading");if(enableButtons){this.$btnc.find("button").prop("disabled",false);}},ajaxResponse:false,contentParsed:"",isAjax:false,isAjaxLoading:false,_parseContent:function(){var that=this;var e=" ";if(typeof this.content==="function"){var res=this.content.apply(this);if(typeof res==="string"){this.content=res;}else{if(typeof res==="object"&&typeof res.always==="function"){this.isAjax=true;this.isAjaxLoading=true;res.always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});this.content=e;}else{this.content=e;}}}if(typeof this.content==="string"&&this.content.substr(0,4).toLowerCase()==="url:"){this.isAjax=true;this.isAjaxLoading=true;var u=this.content.substring(4,this.content.length);$.get(u).done(function(html){that.contentParsed.html(html);}).always(function(data,status,xhr){that.ajaxResponse={data:data,status:status,xhr:xhr};that._contentReady.resolve(data,status,xhr);if(typeof that.contentLoaded==="function"){that.contentLoaded(data,status,xhr);}});}if(!this.content){this.content=e;}if(!this.isAjax){this.contentParsed.html(this.content);this.setContent();that._contentReady.resolve();}},_stopCountDown:function(){clearInterval(this.autoCloseInterval);if(this.$cd){this.$cd.remove();}},_startCountDown:function(){var that=this;var opt=this.autoClose.split("|");if(opt.length!==2){console.error("Invalid option for autoClose. example 'close|10000'");return false;}var button_key=opt[0];var time=parseInt(opt[1]);if(typeof this.buttons[button_key]==="undefined"){console.error("Invalid button key '"+button_key+"' for autoClose");return false;}var seconds=Math.ceil(time/1000);this.$cd=$(' ('+seconds+")").appendTo(this["$_"+button_key]);this.autoCloseInterval=setInterval(function(){that.$cd.html(" ("+(seconds-=1)+") ");if(seconds<=0){that["$$"+button_key].trigger("click");that._stopCountDown();}},1000);},_getKey:function(key){switch(key){case 192:return"tilde";case 13:return"enter";case 16:return"shift";case 9:return"tab";case 20:return"capslock";case 17:return"ctrl";case 91:return"win";case 18:return"alt";case 27:return"esc";case 32:return"space";}var initial=String.fromCharCode(key);if(/^[A-z0-9]+$/.test(initial)){return initial.toLowerCase();}else{return false;}},reactOnKey:function(e){var that=this;var a=$(".jconfirm");if(a.eq(a.length-1)[0]!==this.$el[0]){return false;}var key=e.which;if(this.$content.find(":input").is(":focus")&&/13|32/.test(key)){return false;}var keyChar=this._getKey(key);if(keyChar==="esc"&&this.escapeKey){if(this.escapeKey===true){this.$scrollPane.trigger("click");}else{if(typeof this.escapeKey==="string"||typeof this.escapeKey==="function"){var buttonKey;if(typeof this.escapeKey==="function"){buttonKey=this.escapeKey();}else{buttonKey=this.escapeKey;}if(buttonKey){if(typeof this.buttons[buttonKey]==="undefined"){console.warn("Invalid escapeKey, no buttons found with key "+buttonKey);}else{this["$_"+buttonKey].trigger("click");}}}}}$.each(this.buttons,function(key,button){if(button.keys.indexOf(keyChar)!==-1){that["$_"+key].trigger("click");}});},setDialogCenter:function(){console.info("setDialogCenter is deprecated, dialogs are centered with CSS3 tables");},_unwatchContent:function(){clearInterval(this._timer);},close:function(onClosePayload){var that=this;if(typeof this.onClose==="function"){this.onClose(onClosePayload);}this._unwatchContent();$(window).unbind("resize."+this._id);$(window).unbind("keyup."+this._id);$(window).unbind("jcKeyDown."+this._id);if(this.draggable){$(window).unbind("mousemove."+this._id);$(window).unbind("mouseup."+this._id);this.$titleContainer.unbind("mousedown");}that.$el.removeClass(that.loadedClass);$("body").removeClass("jconfirm-no-scroll-"+that._id);that.$jconfirmBoxContainer.removeClass("jconfirm-no-transition");setTimeout(function(){that.$body.addClass(that.closeAnimationParsed);that.$jconfirmBg.addClass("jconfirm-bg-h");var closeTimer=(that.closeAnimation==="none")?1:that.animationSpeed;setTimeout(function(){that.$el.remove();var l=w.jconfirm.instances;var i=w.jconfirm.instances.length-1;for(i;i>=0;i--){if(w.jconfirm.instances[i]._id===that._id){w.jconfirm.instances.splice(i,1);}}if(!w.jconfirm.instances.length){if(that.scrollToPreviousElement&&w.jconfirm.lastFocused&&w.jconfirm.lastFocused.length&&$.contains(document,w.jconfirm.lastFocused[0])){var $lf=w.jconfirm.lastFocused;if(that.scrollToPreviousElementAnimate){var st=$(window).scrollTop();var ot=w.jconfirm.lastFocused.offset().top;var wh=$(window).height();if(!(ot>st&&ot<(st+wh))){var scrollTo=(ot-Math.round((wh/3)));$("html, body").animate({scrollTop:scrollTo},that.animationSpeed,"swing",function(){$lf.focus();});}else{$lf.focus();}}else{$lf.focus();}w.jconfirm.lastFocused=false;}}if(typeof that.onDestroy==="function"){that.onDestroy();}},closeTimer*0.4);},50);return true;},open:function(){if(this.isOpen()){return false;}this._buildHTML();this._bindEvents();this._open();return true;},setStartingPoint:function(){var el=false;if(this.animateFromElement!==true&&this.animateFromElement){el=this.animateFromElement;w.jconfirm.lastClicked=false;}else{if(w.jconfirm.lastClicked&&this.animateFromElement===true){el=w.jconfirm.lastClicked;w.jconfirm.lastClicked=false;}else{return false;}}if(!el){return false;}var offset=el.offset();var iTop=el.outerHeight()/2;var iLeft=el.outerWidth()/2;iTop-=this.$jconfirmBox.outerHeight()/2;iLeft-=this.$jconfirmBox.outerWidth()/2;var sourceTop=offset.top+iTop;sourceTop=sourceTop-this._scrollTop();var sourceLeft=offset.left+iLeft;var wh=$(window).height()/2;var ww=$(window).width()/2;var targetH=wh-this.$jconfirmBox.outerHeight()/2;var targetW=ww-this.$jconfirmBox.outerWidth()/2;sourceTop-=targetH;sourceLeft-=targetW;if(Math.abs(sourceTop)>wh||Math.abs(sourceLeft)>ww){return false;}this.$jconfirmBoxContainer.css("transform","translate("+sourceLeft+"px, "+sourceTop+"px)");},_open:function(){var that=this;if(typeof that.onOpenBefore==="function"){that.onOpenBefore();}this.$body.removeClass(this.animationParsed);this.$jconfirmBg.removeClass("jconfirm-bg-h");this.$body.focus();that.$jconfirmBoxContainer.css("transform","translate("+0+"px, "+0+"px)");setTimeout(function(){that.$body.css(that._getCSS(that.animationSpeed,1));that.$body.css({"transition-property":that.$body.css("transition-property")+", margin"});that.$jconfirmBoxContainer.addClass("jconfirm-no-transition");that._modalReady.resolve();if(typeof that.onOpen==="function"){that.onOpen();}that.$el.addClass(that.loadedClass);},this.animationSpeed);},loadedClass:"jconfirm-open",isClosed:function(){return !this.$el||this.$el.parent().length===0;},isOpen:function(){return !this.isClosed();},toggle:function(){if(!this.isOpen()){this.open();}else{this.close();}}};w.jconfirm.instances=[];w.jconfirm.lastFocused=false;w.jconfirm.pluginDefaults={template:'
    ',title:"Hello",titleClass:"",type:"default",typeAnimated:true,draggable:true,dragWindowGap:15,dragWindowBorder:true,animateFromElement:true,alignMiddle:true,smoothContent:true,content:"Are you sure to continue?",buttons:{},defaultButtons:{ok:{action:function(){}},close:{action:function(){}}},contentLoaded:function(){},icon:"",lazyOpen:false,bgOpacity:null,theme:"light",animation:"scale",closeAnimation:"scale",animationSpeed:400,animationBounce:1,escapeKey:true,rtl:false,container:"body",containerFluid:false,backgroundDismiss:false,backgroundDismissAnimation:"shake",autoClose:false,closeIcon:null,closeIconClass:false,watchInterval:100,columnClass:"col-md-4 col-md-offset-4 col-sm-6 col-sm-offset-3 col-xs-10 col-xs-offset-1",boxWidth:"50%",scrollToPreviousElement:true,scrollToPreviousElementAnimate:true,useBootstrap:true,offsetTop:40,offsetBottom:40,bootstrapClasses:{container:"container",containerFluid:"container-fluid",row:"row"},onContentReady:function(){},onOpenBefore:function(){},onOpen:function(){},onClose:function(){},onDestroy:function(){},onAction:function(){}};var keyDown=false;$(window).on("keydown",function(e){if(!keyDown){var $target=$(e.target);var pass=false;if($target.closest(".jconfirm-box").length){pass=true;}if(pass){$(window).trigger("jcKeyDown");}keyDown=true;}});$(window).on("keyup",function(){keyDown=false;});w.jconfirm.lastClicked=false;$(document).on("mousedown","button, a, [jc-source]",function(){w.jconfirm.lastClicked=$(this);});})); +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 customConfirm(opts){ + var okCallback = opts.ok; + var cancelCallback = opts.cancel; + + var defaultOpts = { + title: '提示', + buttons: { + ok: { + text: '确认', + btnClass: 'btn btn-primary', + action: okCallback + }, + cancel: { + text: '取消', + btnClass: 'btn btn-secondary', + action: cancelCallback + }, + } + } + return $.confirm($.extend({}, defaultOpts, opts)) +} +; (function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : @@ -128036,337 +128115,6111 @@ 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"]'); - - $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'); - - $applyIdInput.val(applyId); - $form.data('url', url); - }); - // 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'); +/* + * 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: 'POST', - 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() { - 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(''); + + /** + * 设置 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); + } - var departmentId = $departmentIdInput.val(); + 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,17 @@ html, body { /* 某些情况下,被cm盖住了 */ z-index: 99; } - +/* 图片点击放大的场景,隐藏图片链接 */ +.editormd-image-click-expand .editormd-image-dialog { + height: 234px !important; +} + .editormd-image-click-expand .editormd-image-dialog .image-link { + display: none; + } +/* 解决鼠标框选时,左边第一列没高亮的问题 */ +.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 49c2eab99..9b85acfa8 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -9,7 +9,7 @@ import { Route, Switch } from 'react-router-dom'; -import axios from 'axios'; + import '@icedesign/base/dist/ICEDesignBase.css'; import '@icedesign/base/index.scss'; @@ -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,22 @@ 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, +}) + +const Ecs = Loadable({ + loader: () => import('./modules/ecs/Ecs'), + loading: Loading, +}) + class App extends Component { constructor(props) { super(props) @@ -281,7 +303,19 @@ class App extends Component { mydisplay:true, }) }; + + 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(() => { this.forceUpdate() @@ -291,7 +325,6 @@ class App extends Component { }); initAxiosInterceptors(this.props) - // // axios.interceptors.response.use((response) => { // // console.log("response"+response); @@ -337,6 +370,22 @@ class App extends Component { + {/*题库*/} + { + + return () + } + }> + {/*题库*/} + { + + return () + } + }> {/*众包创新*/} {/*认证*/} @@ -365,6 +414,13 @@ class App extends Component { } }> + { + return () + } + }> + @@ -420,6 +476,14 @@ class App extends Component { (props)=>() } > + () + }/> + () + }/> diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 939d2cdaa..025db7f5c 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -38,17 +38,13 @@ export function initAxiosInterceptors(props) { // https://github.com/axios/axios/issues/1497 // TODO 读取到package.json中的配置? - var proxy = "http://localhost:3000" - // proxy = "http://testbdweb.trustie.net" - // proxy = "http://testbdweb.educoder.net" - // proxy = "https://testeduplus2.educoder.net" - proxy="http://47.96.87.25:48080" - // wy - proxy="https://pre-newweb.educoder.net" - - // wy - // proxy="http://192.168.2.63:3001" - + var proxy = "http://localhost:3000" + // proxy = "http://testbdweb.trustie.net" + // proxy = "http://testbdweb.educoder.net" + // proxy = "https://testeduplus2.educoder.net" + //proxy="http://47.96.87.25:48080" + proxy="https://pre-newweb.educoder.net" + proxy="https://test-newweb.educoder.net" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 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 bdd4584f4..c80497509 100644 --- a/public/react/src/common/Env.js +++ b/public/react/src/common/Env.js @@ -1,3 +1,8 @@ export function isDev() { return window.location.port === "3007"; -} \ No newline at end of file +} + +// const isMobile +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 1d7c66dbb..ec4659de7 100644 --- a/public/react/src/common/educoder.js +++ b/public/react/src/common/educoder.js @@ -20,8 +20,9 @@ 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 } from './Env' +export { isDev as isDev, isMobile } from './Env' export { toStore as toStore, fromStore as fromStore } from './Store' @@ -62,7 +63,7 @@ export { default as Clappr } from './components/media/Clappr' export { default as AliyunUploader } from './components/media/AliyunUploader' -export { default as ImageLayerHook } from './hooks/ImageLayerHook' +export { default as ImageLayer2 } from './hooks/ImageLayer2' // 外部 export { default as CBreadcrumb } from '../modules/courses/common/CBreadcrumb' diff --git a/public/react/src/common/hooks/ImageLayerHook.js b/public/react/src/common/hooks/ImageLayer2.js similarity index 96% rename from public/react/src/common/hooks/ImageLayerHook.js rename to public/react/src/common/hooks/ImageLayer2.js index f41cfb0d2..2b1979c74 100644 --- a/public/react/src/common/hooks/ImageLayerHook.js +++ b/public/react/src/common/hooks/ImageLayer2.js @@ -2,7 +2,7 @@ import React, { useState, useEffect, memo } from 'react'; import ImageLayer from '../../modules/page/layers/ImageLayer'; import { isImageExtension } from 'educoder'; const $ = window.$; -function ImageLayerHook(props) { +function ImageLayer2(props) { const [showImage, setShowImage] = useState(false) const [imageSrc, setImageSrc] = useState('') @@ -45,4 +45,4 @@ function ImageLayerHook(props) { ) } -export default memo(ImageLayerHook) \ No newline at end of file +export default memo(ImageLayer2) \ No newline at end of file diff --git a/public/react/src/common/util/ShareUtil.js b/public/react/src/common/util/ShareUtil.js new file mode 100644 index 000000000..bd34e2edb --- /dev/null +++ b/public/react/src/common/util/ShareUtil.js @@ -0,0 +1,135 @@ +import axios from 'axios' +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) + } +} +const urlDoneMap = {} +function requestForSignatrue (callback) { + const currentUrl = window.location.href.split('#')[0] + + if (window.wx) { + if (urlDoneMap[currentUrl]) { + callback && callback() + } else { + const wx = window.wx + const url = '/wechats/js_sdk_signature.json' + urlDoneMap[currentUrl] = true + // window.encodeURIComponent() + axios.post(url, { + 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, + signature: data.signature, + jsApiList: [ + 'onMenuShareTimeline',// + 'onMenuShareAppMessage', + 'onMenuShareQQ', + 'onMenuShareWeibo', + 'onMenuShareQZone' + ] + }); + wx.ready(function () { + callback && callback() + }); + wx.error(function (res) { + console.log('wx is error') + console.log(res) + //alert(res.errMsg);//错误提示 + }); + }).catch((error) => { + console.log(error) + }) + } + } +} +/** + 实践课程 平台提供涵盖基础入门、案例实践和创新应用的完整实训项目体系,通过由浅入深的实训路径,帮助学生快速提升实战能力。 + 实训项目 覆盖不同专业的IT实验和实训,每周更新,无需配置本机实验环境,随时随地开启企业级真实实训。 + 翻转课堂 自动评测实训任务,支持技能统计,提供教学活动分析报告,减轻教师和助教的辅导压力,免去作业发布和批改的困扰,实时了解学生学习情况,全面提升教师施教效率和水平。 + 单个课程和实训 获取课程/实训的简介 该课程或者实训展示的缩略图 + + */ +export function configShareForIndex (path) { + requestForSignatrue(() => { + 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 () { + requestForSignatrue(() => { + 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 () { + requestForSignatrue(() => { + 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 () { + requestForSignatrue(() => { + 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, imgUrl, path) { + requestForSignatrue(() => { + console.log('configShareForCustom', host) + const _url = window.location.href.split('#')[0]; + var shareData = { + title: title, + desc: desc, + link: path ? `${host}/${path}` : _url, + 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 0e0d7be1b..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 } @@ -525,7 +527,10 @@ pop_box_new(htmlvalue, 480, 182); }) // test - // var data = {"st":0,"discusses_count":12,"game_count":6,"record_onsume_time":5.303,"prev_game":"q67plhfjaogy","next_game":"lfrwm2ohiate","praise_count":0,"user_praise":false,"time_limit":180,"tomcat_url":"http://47.98.226.234","is_teacher":true,"myshixun_manager":false,"game":{"id":1964918,"myshixun_id":510423,"user_id":73892,"created_at":"2019-06-24T11:22:58.000+08:00","updated_at":"2019-06-25T11:15:48.000+08:00","status":0,"final_score":0,"challenge_id":573,"open_time":"2019-06-24T11:22:58.000+08:00","identifier":"yrsxolqk6zcp","answer_open":0,"end_time":null,"retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":null,"modify_time":null,"star":0,"cost_time":3966,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":573,"shixun_id":186,"subject":"应用模型做预测","position":4,"task_pass":"####本关任务\r\n本关卡学习如何应用机器学习模型来做预测。\r\n\r\n####相关知识\r\n在前一关卡中,我们一起探讨了机器学习的一般原理,并建立了一个非常简单的电影评分模型Model 0:\r\n\r\n评分 = **大众对电影的平均评分** + **用户个人的给分偏好** + **电影的评分偏好**\r\n\r\n针对这个模型,我们设计了一个非常朴素的预测模型Baseline,直接从数据集中统计得到上述三个参数的值。\r\n\r\n在本关卡中,我们将应用这个模型对用户和电影的评分做出预测。\r\n\r\n####编程要求\r\n回顾Model 0的预测评分公式:\r\n```latex\r\nf(u,m)=g+\\alpha(u)+\\beta(m)\r\n```\r\n\r\n我们的Baseline模型得到了$$g$$、$$\\alpha$$和$$\\beta$$三种参数,下面我们实现predict函数,来对测试数据集中未知的用户电影评分进行预测,需要填充的代码块如下:\r\n```python\r\n# -*- coding:utf-8 -*-\r\n\r\ndef predict(g, alpha, beta, test_data):\r\n\t\"\"\"预测用户对电影的评分\r\n\t参数:\r\n\t\tg - 浮点数,模型参数平均电影评分\r\n\t\talpha - 浮点数组,用户评分偏差参数数组\r\n\t\tbeta - 浮点数组,电影评分偏差参数数组\r\n\t\ttest_data - Pandas的DataFrame对象,有两列'user','movie',是测试数据集\r\n\t返回值:\r\n\t\tret - 浮点数数组,预测的评分数组,举例ret[10],表示第10组用户和电影对的评分值\r\n\t\"\"\"\t\r\n\tret = []\r\n\tN = len(alpha)\r\n\tM = len(beta)\r\n\t\r\n\t# 请在此添加实现代码\r\n\t#********** Begin *********#\r\n\t\r\n\t#********** End *********#\r\n\t\r\n\treturn ret\r\n```\r\n\r\n####本关任务\r\n本关卡的测试数据来自内置测试文件,平台将比对您所编写函数的预测评分与正确评分,只有所有数据全部计算正确才能进入下一关。","score":500,"path":"src/step4/doprediction.py","st":0,"web_route":null,"modify_time":null},"shixun":{"id":186,"name":"理解机器学习基本概念:从电影评分预测讲起","user_id":24758,"gpid":3676,"visits":622,"created_at":"2017-08-25T18:07:41.000+08:00","updated_at":"2019-06-02T11:05:20.000+08:00","status":2,"language":"MachineLearning","authentication":false,"identifier":"58DRWG63","trainee":3,"major_id":635,"webssh":0,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2017-09-29T21:42:16.000+08:00","reset_time":"2017-09-29T21:42:16.000+08:00","publish_time":"2017-09-29T10:58:13.000+08:00","closer_id":null,"end_time":null,"git_url":"educoder/58drwg63","vnc":false,"myshixuns_count":318,"challenges_count":6,"use_scope":0,"mirror_script_id":0,"image_text":null,"code_hidden":false,"task_pass":false,"exec_time":180,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"educoder/58drwg63","averge_star":4.9,"opening_time":null,"users_count":10,"forbid_copy":false,"pod_life":0},"myshixun":{"id":510423,"shixun_id":186,"is_public":true,"user_id":73892,"gpid":null,"created_at":"2019-06-24T11:22:55.000+08:00","updated_at":"2019-06-24T13:56:40.000+08:00","status":0,"identifier":"7pkwxim9eh","commit_id":"ff7c6652fdfdf62eaa1316d39400ebdbd6cb81fb","modify_time":"2017-09-29T21:42:16.000+08:00","reset_time":"2017-09-29T21:42:16.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-06-24T11:22:55.000+08:00","repo_name":"p35840769/7pkwxim9eh20190624112255"},"user":{"user_id":73892,"login":"p35840769","name":"韩半安","grade":6895,"image_url":"avatars/User/b","school":"国防科技大学","identity":6},"tpm_modified":false,"tpm_cases_modified":false,"mirror_name":["MachineLearning"],"has_answer":true,"test_sets":[{"is_public":true,"result":false,"input":"771 253 360 99 8 759 976 387 873 829 437 53 854 148 447 179 246 810 158 653 583 929 691 892 263 230 637 221 7 652 127 965 767","output":"3.577 -0.329 2.648 4.727 4.351 2.616 3.496 3.059 3.470 3.166 3.064 2.716 3.712 4.003 3.064 3.462 4.004 2.067 3.860 0.121 3.807 3.735 4.230 3.137 4.431 2.468 4.018 5.218 4.351 4.121 4.050 4.587 3.777","actual_output":"Traceback (most recent call last):\r\n File \"src/step4/main.py\", line 3, in \u003cmodule\u003e\r\n from doprediction import predict\r\nImportError: cannot import name 'predict'\r\n","compile_success":1},{"is_public":false,"result":false,"compile_success":1}],"allowed_unlock":true,"last_compile_output":"共有2组测试集,其中有2组测试结果不匹配。详情如下:","test_sets_count":2,"sets_error_count":2} + // var data = {"st":0,"discusses_count":0,"game_count":3,"record_onsume_time":0.36,"prev_game":null,"next_game":"7p9xwo2hklqv","praise_count":0,"user_praise":false,"time_limit":20,"tomcat_url":"http://47.96.157.89","is_teacher":false,"myshixun_manager":true,"game":{"id":2192828,"myshixun_id":580911,"user_id":57844,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:51:05.000+08:00","status":2,"final_score":0,"challenge_id":10010,"open_time":"2019-09-03T15:50:49.000+08:00","identifier":"hknvz4oaw825","answer_open":0,"end_time":"2019-09-03T15:51:04.000+08:00","retry_status":0,"resubmit_identifier":null,"test_sets_view":false,"picture_path":null,"accuracy":1.0,"modify_time":"2019-09-03T15:23:33.000+08:00","star":0,"cost_time":14,"evaluate_count":1,"answer_deduction":0},"challenge":{"id":10010,"shixun_id":3516,"subject":"1.1 列表操作","position":1,"task_pass":"[TOC]\n\n---\n\n####任务描述\n\n\n数据集a包含1-10共10个整数,请以a为输入数据,编写python程序,实现如下功能:\n①\t用2种方法输出a中所有奇数\n②\t输出大于3,小于7的偶数\n③\t用2种方法输出[1,2,3,…10,11,…20]\n④\t输出a的最大值、最小值。\n⑤\t用2种方法输出[10,9,…2,1]\n⑥\t输出[1,2,3,1,2,3,1,2,3,1,2,3]\n\n\n####相关知识\n\n\n请自行学习相关知识\n\n\n---\n开始你的任务吧,祝你成功!","score":100,"path":"1-1-stu.py","st":0,"web_route":null,"modify_time":"2019-09-03T15:23:33.000+08:00","exec_time":20,"praises_count":0},"shixun":{"id":3516,"name":"作业1——Python程序设计","user_id":77620,"gpid":null,"visits":23,"created_at":"2019-09-03T14:18:17.000+08:00","updated_at":"2019-09-03T15:58:16.000+08:00","status":0,"language":null,"authentication":false,"identifier":"6lzjig58","trainee":1,"major_id":null,"webssh":2,"homepage_show":false,"hidden":false,"fork_from":null,"can_copy":true,"modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","publish_time":null,"closer_id":null,"end_time":null,"git_url":null,"vnc":null,"myshixuns_count":3,"challenges_count":3,"use_scope":0,"mirror_script_id":20,"image_text":null,"code_hidden":false,"task_pass":true,"exec_time":20,"test_set_permission":true,"sigle_training":false,"hide_code":false,"multi_webssh":false,"excute_time":null,"repo_name":"p09218567/6lzjig58","averge_star":5.0,"opening_time":null,"users_count":1,"forbid_copy":false,"pod_life":0},"myshixun":{"id":580911,"shixun_id":3516,"is_public":true,"user_id":57844,"gpid":null,"created_at":"2019-09-03T15:50:49.000+08:00","updated_at":"2019-09-03T15:59:04.000+08:00","status":0,"identifier":"k36hm4rwav","commit_id":"f25e1713882156480fc45ce0af57eff395a5037f","modify_time":"2019-09-03T14:18:17.000+08:00","reset_time":"2019-09-03T14:18:17.000+08:00","system_tip":false,"git_url":null,"onclick_time":"2019-09-03T15:50:49.000+08:00","repo_name":"p53276410/k36hm4rwav20190903155049"},"user":{"user_id":57844,"login":"p53276410","name":"文振乾","grade":24624,"identity":1,"image_url":"avatars/User/57844","school":"EduCoder团队"},"tpm_modified":true,"tpm_cases_modified":false,"mirror_name":["Python3.6"],"has_answer":false,"test_sets":[{"is_public":true,"result":true,"input":"","output":"result of a:\n[1, 3, 5, 7, 9]\n[1, 3, 5, 7, 9]\nresult of b:\n[2, 4, 6, 8, 10]\nresult of c:\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\nresult of d:\nThe minimum is:1\nThe maxium is:10\nresult of e:\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\nresult of f:\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\n","actual_output":"result of a:\r\n[1, 3, 5, 7, 9]\r\n[1, 3, 5, 7, 9]\r\nresult of b:\r\n[2, 4, 6, 8, 10]\r\nresult of c:\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]\r\nresult of d:\r\nThe minimum is:1\r\nThe maxium is:10\r\nresult of e:\r\n[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]\r\n[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\r\nresult of f:\r\n[10, 9, 8, 10, 9, 8, 10, 9, 8, 10, 9, 8]\r\n","compile_success":1,"ts_time":0.05,"ts_mem":8.77}],"allowed_unlock":true,"last_compile_output":"compile successfully","test_sets_count":1,"sets_error_count":0} + // data.test_sets[0].actual_output = data.test_sets[0].actual_output.replace(/\r\n/g, '\n') + // data.test_sets[0].output = data.test_sets[0].output.replace(/\r\n/g, '\n') + // console.log(JSON.stringify(data)) // data.shixun.vnc = true // data.vnc_url= "http://47.96.157.89:41158/vnc_lite.html?password=headless" @@ -874,6 +879,7 @@ pop_box_new(htmlvalue, 480, 182); return (
              + style={{ 'float': 'left', 'marginTop': '6px', 'fontSize': '12px', 'color': '#ff6800'}}> 请勿粘贴答案,否则将造成账号禁用等后果!
              diff --git a/public/react/src/modules/comment/Comments.js b/public/react/src/modules/comment/Comments.js index ae246197c..836b520cc 100644 --- a/public/react/src/modules/comment/Comments.js +++ b/public/react/src/modules/comment/Comments.js @@ -383,12 +383,12 @@ class Comments extends Component { {/* |*/} - this.initReply(item) } > - + } {/* |*/} diff --git a/public/react/src/modules/courses/Index.js b/public/react/src/modules/courses/Index.js index 7da04dd0e..f9f80a9da 100644 --- a/public/react/src/modules/courses/Index.js +++ b/public/react/src/modules/courses/Index.js @@ -232,7 +232,7 @@ const GraduationTasksquestions= Loadable({ //毕设任务列表 const GraduationTaskssettinglist= Loadable({ - loader: () => import('./graduation/tasks/GraduationTaskssettinglist'), + loader: () => import('./graduation/tasks/GraduationTaskDetail'), loading: Loading, }) @@ -264,25 +264,11 @@ 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) { @@ -310,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; @@ -328,9 +315,33 @@ class CoursesIndex extends Component{ if(isNaN(id)){ return } + + const querys = this.props.location.search; + var dataqueryss={} + try { + var foqus=this.foo(querys); + if(JSON.stringify(foqus) ==="{}"){ + this.setState({ + dataquerys:{}, + }); + }else{ + this.setState({ + dataquerys:foqus, + }); + dataqueryss=foqus; + } + }catch (e) { + this.setState({ + dataquerys:{}, + }) + } // let id=this.props.match.params.coursesId; let url ="/courses/"+id+"/left_banner.json" - axios.get(url).then((response) => { + axios.get(url, + {params: + dataqueryss + } + ).then((response) => { if(response!=undefined){ if(response.data&&response.data){ this.setState({ @@ -343,7 +354,28 @@ class CoursesIndex extends Component{ } } }) - } + }; + foo=(url)=> { + var json = {}; + var regExp = /[\?\&](\w+)(=?)(\w*)/g; + var arr; + do { + arr = regExp.exec(url); + // console.log(arr); // arr = [完整的字符串, key, 等号或'', value或''] + + if (arr) { + var key = arr[1]; + var value = arr[3]; + // arr[2] === ''时, value = undefined + if (!arr[2]) + value = undefined; + + json[key] = value; + } + } while (arr); + + return json; + }; locationNav=(list)=>{ if(list){ @@ -470,30 +502,12 @@ class CoursesIndex extends Component{ // console.log(commons) return ( - {/*毕设任务题库详情*/} - () - } - > - {/*毕设内容题库详情*/} - () - } - > - {/*分组作业题库详情*/} - () - } - > - {/* 普通作业题库详情*/} - () - } - > + {/*排序*/} + () + } + > {/* 资源列表页 */} {/* 新建作品 */} - () } > {/* 修改作品 */} - () } @@ -574,7 +588,7 @@ class CoursesIndex extends Component{ {/* 设置毕设任务 https://www.trustie.net/issues/19981 */} - () } @@ -582,19 +596,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/boards/BoardsNew.js b/public/react/src/modules/courses/boards/BoardsNew.js index 58cd0c02b..0222907d3 100644 --- a/public/react/src/modules/courses/boards/BoardsNew.js +++ b/public/react/src/modules/courses/boards/BoardsNew.js @@ -181,15 +181,16 @@ class BoardsNew extends Component{ } // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) - }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) }); + } } onAttachmentRemove = (file) => { - if(file.response!=undefined){ - confirm({ + if(!file.percent || file.percent == 100){ + this.props.confirm({ // title: '确定要删除这个附件吗?', - title: '是否确认删除?', + content: '是否确认删除?', okText: '确定', cancelText: '取消', @@ -286,7 +287,7 @@ class BoardsNew extends Component{ const isAdmin = this.props.isAdmin() const courseId=this.props.match.params.coursesId; const boardId = this.props.match.params.boardId - + const isCourseEnd = this.props.isCourseEnd() return(
              {menu} { - isAdmin && + isAdmin && !isCourseEnd &&
              this.refs['addDirModal'].open()}> diff --git a/public/react/src/modules/courses/boards/TopicDetail.js b/public/react/src/modules/courses/boards/TopicDetail.js index 542157bfb..8ecc85565 100644 --- a/public/react/src/modules/courses/boards/TopicDetail.js +++ b/public/react/src/modules/courses/boards/TopicDetail.js @@ -527,6 +527,7 @@ class TopicDetail extends Component { // TODO 图片上传地址 const courseId=this.props.match.params.coursesId; const boardId = this.props.match.params.boardId + const isCourseEnd = this.props.isCourseEnd() return (
              {/* fl with100 */} +
              {(description || (attachments && attachments.length != 0)) &&
              @@ -218,7 +219,8 @@ class CommonWorkAppraise extends Component{ {item.filesize} {/*{item.delete===true?:""}*/} - {item.delete===true?:""} + {item.delete===true?:""} + {/* style={{display: 'none'}} */}
              ) })} @@ -246,14 +248,16 @@ class CommonWorkAppraise extends Component{
              } - + {is_evaluation != true && project_info && project_info.name &&
              关联项目
              - {project_info.name} + {project_info.name}
              } diff --git a/public/react/src/modules/courses/busyWork/CommonWorkAppraiseReviseAttachments.js b/public/react/src/modules/courses/busyWork/CommonWorkAppraiseReviseAttachments.js index d12099d38..31fd4b9e6 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkAppraiseReviseAttachments.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkAppraiseReviseAttachments.js @@ -33,7 +33,7 @@ function CommonWorkAppraiseReviseAttachments(props) { {item.title} {item.filesize} - {item.delete===true?:""} + {item.delete===true?:""}
              ) })} diff --git a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js index 5693b3788..8985aa07e 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js @@ -286,8 +286,8 @@ class CommonWorkDetailIndex extends Component{ seeworks={undefined} reviseAttachmentUrl={`/student_works/${work_id || studentWorkId}/revise_attachment.json`} />:""} - 补交附件 @@ -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 &&
              - { isAdmin &&
                + { isAdmin && hasData &&
                  @@ -713,7 +715,7 @@ class CommonWorkList extends Component{ {
                  - + {hasData && { isAdmin ? (!!all_member_count) && {work_count || '0'}个检索结果({all_member_count} 学生) @@ -725,7 +727,7 @@ class CommonWorkList extends Component{ {left_time.time} } - + } {/* { isAdminOrStudent && student_works && !!student_works.length &&

                  @@ -815,10 +817,8 @@ class CommonWorkList extends Component{

                  diff --git a/public/react/src/modules/courses/busyWork/CommonWorkPost.js b/public/react/src/modules/courses/busyWork/CommonWorkPost.js index fec3f02a1..ce552fa50 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkPost.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkPost.js @@ -131,7 +131,6 @@ class CommonWorkPost extends Component{ let coursesId=this.props.match.params.coursesId; window.location.href="courses/"+coursesId+"/graduation_tasks/"+workId+"/appraise"; - // window.location.href="/courses/"+coursesId+"/graduation/graduation_tasks/"+workId+"/"+workId+"/works/edit"; } handleSubmit=(e) => { @@ -291,7 +290,7 @@ class CommonWorkPost extends Component{ } // 附件相关 START handleChange = (info) => { - if (info.file.status === 'uploading' || info.file.status === 'done') { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) }); @@ -320,11 +319,19 @@ class CommonWorkPost extends Component{ // ModalSave: ()=>this.deleteAttachment(file), // ModalCancel:this.cancelAttachment // }) - if(file.response!=undefined){ - this.deleteAttachment(file) + + if(!file.percent || file.percent == 100){ + this.props.confirm({ + content: '是否确认删除?', + onOk: () => { + this.deleteAttachment(file) + }, + onCancel() { + console.log('Cancel'); + }, + }); return false; } - } cancelAttachment=()=>{ @@ -638,7 +645,7 @@ render(){ {/*>*/} {/**/} - {`${current_user ? current_user.username : ''} ${ this.isEdit ? '编辑' : '提交'}作品` } + {`${current_user ? current_user.real_name : ''} ${ this.isEdit ? '编辑' : '提交'}作品` }

                  diff --git a/public/react/src/modules/courses/busyWork/NewWork.js b/public/react/src/modules/courses/busyWork/NewWork.js index fb2d18de0..e11eca9e2 100644 --- a/public/react/src/modules/courses/busyWork/NewWork.js +++ b/public/react/src/modules/courses/busyWork/NewWork.js @@ -3,247 +3,127 @@ import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Moda import axios from 'axios' import '../css/busyWork.css' import '../css/Courses.css' -import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder' +import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll + , 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) => { - let contentFileList = info.fileList; - this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); - } - handleAnswerUploadChange = (info) => { - let answerFileList = info.fileList; - this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); - } - - onAttachmentRemove = (file, stateName) => { - if(file.response!=undefined){ + onAttachmentRemove = (file, stateName) => { + if(!file.percent || file.percent == 100){ this.props.confirm({ content: '是否确认删除?', @@ -259,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: `${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; - }, - }; + 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..c52350c78 --- /dev/null +++ b/public/react/src/modules/courses/busyWork/NewWorkForm.js @@ -0,0 +1,548 @@ +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._scrollToTop() + // 阻止setValue的滚动 + // $(window).scroll( function() { + // $("html").scrollTop(0) + // $(window).unbind("scroll"); + // }); + /** + setValue会调用到 codemirror的 o.scrollIntoView(i), 会导致滚动条跳动 + */ + // $('.editormd').parent().css('position', 'fixed').css('left', '-1000px') + // this.contentMdRef.current.setValue(data.description || '') + // this.answerMdRef.current.setValue(data.reference_answer || '') + // setTimeout(() => { + // $('.editormd').parent().css('position', '').css('left', 'auto') + // }, 100); + // }, 500) + + this.props.form.setFieldsValue({ + title: data.name, + description: data.description || '', + reference_answer: data.reference_answer || '', + }); + + }) + } else { // new + + } + // this._scrollToTop() + } + _scrollToTop = () => { + // setTimeout(() => { + $("html").scrollTop(0) + // $("html").animate({ scrollTop: 0 }) + // }, 1000) + } + + // 输入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') + this._scrollToTop() + } + + 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 + }=this.state + const { current_user } = this.props + + const courseId = this.state.course_id || this.props.match.params.coursesId ; + this.isEdit = this.isEdit || this.props.match.url.indexOf('/edit') != -1 + if ((this.isEdit) && !this.state.description) { + 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/common/WorkDetailPageHeader.js b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js index c9d99696a..68a16d89e 100644 --- a/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js +++ b/public/react/src/modules/courses/busyWork/common/WorkDetailPageHeader.js @@ -86,7 +86,7 @@ class WorkDetailPageHeader extends Component{ background: #fff; } .workDetailPageHeader .summaryname { - line-height:30px + line-height:28px } `} :""} -
                  补交附件 diff --git a/public/react/src/modules/courses/busyWork/commonWork.js b/public/react/src/modules/courses/busyWork/commonWork.js index 9f98b9294..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() } } @@ -124,7 +125,7 @@ class commonWork extends Component{ if(search!=""){ url+="&search="+search; } - axios.get((url)).then((result)=>{ + axios.get(encodeURI(url)).then((result)=>{ if(result.status==200){ this.setState({ mainList:result.data, @@ -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/CBreadcrumb.js b/public/react/src/modules/courses/common/CBreadcrumb.js index 6e3343edf..bf98a3a36 100644 --- a/public/react/src/modules/courses/common/CBreadcrumb.js +++ b/public/react/src/modules/courses/common/CBreadcrumb.js @@ -16,7 +16,7 @@ class CBreadcrumb extends Component{ return '' } if (item.to) { - return + return {item.name} {separator ? {separator} : @@ -24,7 +24,7 @@ class CBreadcrumb extends Component{ } } else { - return {item.name} + return {item.name} } })}

                  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/common/comments/CCommentItem.js b/public/react/src/modules/courses/common/comments/CCommentItem.js index 2415dd0b0..5d904a36b 100644 --- a/public/react/src/modules/courses/common/comments/CCommentItem.js +++ b/public/react/src/modules/courses/common/comments/CCommentItem.js @@ -238,7 +238,8 @@ class CCommentItem extends Component{
                  -
                  +
                  @@ -373,8 +374,8 @@ class CCommentItem extends Component{ : ''} */}
                  - {/* style={{ height: '130px'}} */} -

                  + {/* 去掉了orig_reply 影响到i标签 */} +

                  {/* 第二排右侧按钮区域 */} {/* ${this.state.show_reply ? '回复' : '申诉'} */} {(show_reply || show_appeal) && diff --git a/public/react/src/modules/courses/common/comments/CommonReply.js b/public/react/src/modules/courses/common/comments/CommonReply.js index dae21949c..8b7817e85 100644 --- a/public/react/src/modules/courses/common/comments/CommonReply.js +++ b/public/react/src/modules/courses/common/comments/CommonReply.js @@ -250,7 +250,7 @@ class CommonReply extends Component{ } `} 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 3cbd04fd1..437471436 100644 --- a/public/react/src/modules/courses/coursesDetail/CoursesBanner.js +++ b/public/react/src/modules/courses/coursesDetail/CoursesBanner.js @@ -94,9 +94,30 @@ class CoursesBanner extends Component { this.updatabanner() } updatabanner=()=>{ + const query = this.props.location.search; + var dataqueryss={} + try { + var foqus=this.foo(query); + if(JSON.stringify(foqus) ==="{}"){ + this.setState({ + dataquerys:{}, + }); + }else{ + this.setState({ + dataquerys:foqus, + }); + dataqueryss=foqus; + } + }catch (e) { + this.setState({ + dataquerys:{}, + }) + } let courseId = this.props.match.params.coursesId; let url = "/courses/" + courseId + "/top_banner.json" - axios.get(url).then((result) => { + axios.get(url,{params: + dataqueryss + }).then((result) => { if( result!=undefined){ let data = result.data; this.setState({ @@ -107,7 +128,28 @@ class CoursesBanner extends Component { this.onloadupdatabanner() } }) - } + }; + foo=(url)=> { + var json = {}; + var regExp = /[\?\&](\w+)(=?)(\w*)/g; + var arr; + do { + arr = regExp.exec(url); + // console.log(arr); // arr = [完整的字符串, key, 等号或'', value或''] + + if (arr) { + var key = arr[1]; + var value = arr[3]; + // arr[2] === ''时, value = undefined + if (!arr[2]) + value = undefined; + + json[key] = value; + } + } while (arr); + + return json; + }; showeditmenu = () => { this.setState({ show: true, @@ -426,7 +468,7 @@ class CoursesBanner extends Component { render() { let { Addcoursestypes, coursedata,excellent, modalsType, modalsTopval, loadtype,modalsBottomval,antIcon,is_guide,AccountProfiletype} = this.state; - + const isCourseEnd = this.props.isCourseEnd() return (
                  { @@ -625,7 +667,7 @@ class CoursesBanner extends Component { ) : ""} - {this.props.isStudent()? this.exitclass()} > 退出课堂 :""} @@ -655,7 +697,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?"": @@ -714,24 +759,24 @@ class CoursesBanner extends Component { position: "relative" }} > -
                • + {!isCourseEnd &&
                • this.addTeacher(true)}> 添加老师 -
                • + } -
                • + {!isCourseEnd &&
                • this.addTeacher(false)}> 添加助教 -
                • + } -
                • + {!isCourseEnd &&
                • this.addStudent()}> 添加学生 -
                • + } {excellent===false?
                • diff --git a/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js b/public/react/src/modules/courses/coursesDetail/CoursesLeftNav.js index 1a7c19824..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, } } @@ -749,13 +751,21 @@ class Coursesleftnav extends Component{ {/*毕业设计*/} {/*{item.type==="graduation"?
                  this.Navmodalnames(1,"attachment",item.id)}>添加目录
                  :""}*/} {/*讨论区*/} - {item.type==="board"?
                  this.Navmodalnames(e,6,"board",item.main_id)}>添加目录
                  :""} + {item.type==="board"?this.props.current_user&&this.props.current_user.course_is_end===true?"":
                  this.Navmodalnames(e,6,"board",item.main_id)}>添加目录
                  :""} {/*分班*/} - {item.type==="course_group"?
                  this.Navmodalnames(e,2,"course_group",item.id)}>添加分班
                  :""} + {item.type==="course_group"?this.props.current_user&&this.props.current_user.course_is_end===true?"":
                  this.Navmodalnames(e,2,"course_group",item.id)}>添加分班
                  :""} {/*分班*/} {/*{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, @@ -798,7 +823,6 @@ class Coursesleftnav extends Component{ // console.log("778"); // console.log("CoursesLeftNav"); - // console.log(this.props); // console.log(course_modules); return( @@ -816,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/AccessoryModal.js b/public/react/src/modules/courses/coursesPublic/AccessoryModal.js index 3b25ceb6d..aadfa770f 100644 --- a/public/react/src/modules/courses/coursesPublic/AccessoryModal.js +++ b/public/react/src/modules/courses/coursesPublic/AccessoryModal.js @@ -40,15 +40,17 @@ class AccessoryModal extends Component{ } // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - console.log(fileList) - // for(var list of fileList ){ - // console.log(fileList) - // } - this.setState({ - fileList:fileList, - Errormessage:false, - }); + 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:fileList, + Errormessage:false, + }); + } } onAttachmentRemove = (file) => { @@ -73,7 +75,7 @@ class AccessoryModal extends Component{ // ModalCancel:this.cancelAttachment // }) // return false; - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.deleteAttachment(file); } } diff --git a/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js b/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js index a9a627387..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) => { @@ -64,7 +67,7 @@ class AccessoryModal2 extends Component{ // ModalCancel:this.cancelAttachment // }) // return false; - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.deleteAttachment(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/CoursesListType.js b/public/react/src/modules/courses/coursesPublic/CoursesListType.js index d5805c0d5..039f96914 100644 --- a/public/react/src/modules/courses/coursesPublic/CoursesListType.js +++ b/public/react/src/modules/courses/coursesPublic/CoursesListType.js @@ -30,7 +30,7 @@ class CoursesListType extends Component { return( { - typelist===undefined?"":typelist.map((item,key)=>{ + typelist===undefined || typelist=== 403 || typelist === 401 || typelist=== 407 || typelist=== 408|| typelist=== 409 || typelist === 500?"":typelist.map((item,key)=>{ return( document.querySelector('.TabsWarp')} key={key}> diff --git a/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js b/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js index 3538aaf57..fea6c79be 100644 --- a/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js +++ b/public/react/src/modules/courses/coursesPublic/CoursesMarkdown.js @@ -139,9 +139,9 @@ 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.setCursor(__Cursor.line, __Cursor.ch - 3); _editorName.cm.focus(); }); $("[type=\"inline\"]").attr("title", "行内公式"); 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..bae89a7ba --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/NewShixunModel.js @@ -0,0 +1,580 @@ +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( + +
                  + + + this.props.hideNewShixunModelType()} + visible={this.props.NewShixunModelType} + height={'100%'} + > + +
                  + +
                  + +
                  +
                  + + 搜索} + 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..f0f45a468 --- /dev/null +++ b/public/react/src/modules/courses/coursesPublic/Newshixunmodel.css @@ -0,0 +1,269 @@ +.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; +} + +.newshixunbottombtn{ + position: fixed; + z-index: 1000; + bottom: 0px; + width: 100%; + height: 63px; + background: rgba(255,255,255,1); + box-shadow: 0px -4px 4px 0px rgba(0,0,0,0.05); +} + + +.mb60shixun{ + margin-bottom: 60px !important; +} + +.padding13-30 { + padding: 13px 30px; + box-sizing: border-box; +} \ No newline at end of file diff --git a/public/react/src/modules/courses/coursesPublic/SelectSetting.js b/public/react/src/modules/courses/coursesPublic/SelectSetting.js index d52b328e2..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) => { @@ -296,7 +296,7 @@ class Selectsetting extends Component{ onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` axios.delete(url, { }) 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 56c85439c..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), + }); + } } } @@ -132,7 +133,7 @@ class Sendresource extends Component{ onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` axios.delete(url, { }) 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/css/busyWork.css b/public/react/src/modules/courses/css/busyWork.css index 140b431df..92427c753 100644 --- a/public/react/src/modules/courses/css/busyWork.css +++ b/public/react/src/modules/courses/css/busyWork.css @@ -1,80 +1,81 @@ - -.polllisthover:hover { - box-shadow: 0px 2px 6px rgba(51,51,51,0.09); - opacity: 1; - border-radius: 2px; -} - -.workList_Item{ - /* padding:20px 30px; */ - display: flex; - background-color: #fff; - margin-bottom: 20px; - padding-top: 10px; -} -p span{ - cursor: default; -} -.mt-5{ margin-top:-5px;} - - -/* ���ѡ��tab */ -.bankNav li{ - float: left; - margin-right: 20px; -} -.bankNav li:last-child{ - margin-right: 0px; -} -.bankNav li.active a{ - color: #fff!important; - background-color: #4CACFF; -} -.bankNav li a{ - display: block; - padding:0px 10px; - height: 28px; - line-height: 28px; - background-color: #F5F5F5; - border-radius: 36px; - color: #666666!important; -} - - - -.task_menu_ul{ - width: 600px; -} - -.task_menu_ul .ant-menu-item,.task_menu_ul .ant-menu-submenu-title{ - padding:0px; - margin-right: 30px; - line-height: 68px; - font-size: 16px; -} -.ant-menu{ - color: #05101a; -} -.task_menu_ul .ant-menu-horizontal{ - border-bottom: none; -} -.task_menu_ul .ant-menu-horizontal > .ant-menu-item:hover{ - border-bottom:2px solid transparent; -} -.task_menu_ul .ant-menu-horizontal > .ant-menu-item-selected{ - border-bottom: 2px solid #4CACFF !important; -} - -.sourceTag a{ - display: block; - float: left; - background-color:#E5F3FF; - padding: 0px 10px; - height: 24px; - line-height: 24px; - color: #4E7A9B; - margin:5px 0px 5px 10px; -} -.sourceTag a.active{ - color: #FFFFFF;background-color:#4CACFF; -} \ No newline at end of file + +.polllisthover:hover { + box-shadow: 0px 2px 6px rgba(51,51,51,0.09); + opacity: 1; + border-radius: 2px; +} + +.workList_Item{ + /* padding:20px 30px; */ + display: flex; + background-color: #fff; + margin-bottom: 20px; + padding-top: 10px; +} +p span{ + cursor: default; +} +.mt-5{ margin-top:-5px;} + + +/* ���ѡ��tab */ +.bankNav li{ + float: left; + margin-right: 20px; +} +.bankNav li:last-child{ + margin-right: 0px; +} +.bankNav li.active a{ + color: #fff!important; + background-color: #4CACFF; +} +.bankNav li a{ + display: block; + padding:0px 10px; + height: 28px; + line-height: 28px; + background-color: #F5F5F5; + border-radius: 36px; + color: #666666!important; +} + + + +.task_menu_ul{ + width: 600px; +} + +.task_menu_ul .ant-menu-item,.task_menu_ul .ant-menu-submenu-title{ + padding:0px; + margin-right: 30px; + line-height: 68px; + font-size: 16px; +} +.ant-menu{ + color: #05101a; +} +.task_menu_ul .ant-menu-horizontal{ + border-bottom: none; +} +.task_menu_ul .ant-menu-horizontal > .ant-menu-item:hover{ + border-bottom:2px solid transparent; +} +.task_menu_ul .ant-menu-horizontal > .ant-menu-item-selected{ + border-bottom: 2px solid #4CACFF !important; +} + +.sourceTag a{ + display: block; + float: left; + background-color:#E5F3FF; + padding: 0px 10px; + height: 24px; + line-height: 24px; + color: #4E7A9B; + margin:5px 0px 5px 10px; +} +.sourceTag a.active{ + color: #FFFFFF;background-color:#4CACFF; +} + 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..65377bb19 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); @@ -497,7 +498,7 @@ class Exercise extends Component{ {/*}*/}

                    -

                    +

                    共{exercises_counts && exercises_counts.exercises_total_counts}个试卷 已发布:{exercises_counts && exercises_counts.exercises_published_counts}个 未发布:{exercises_counts && exercises_counts.exercises_unpublish_counts}个 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..6fdde6aeb 100644 --- a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js +++ b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js @@ -19,9 +19,10 @@ 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"; - +import NoneData from '../../../modules/courses/coursesPublic/NoneData' const Search = Input.Search; const RadioGroup = Radio.Group; const CheckboxGroup = Checkbox.Group; @@ -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} } @@ -1159,6 +1217,7 @@ class Studentshavecompletedthelist extends Component { ) }, ], + exercise_status:0, } // console.log("Studentshavecompletedthelist"); // console.log(props.current_status); @@ -1219,6 +1278,20 @@ class Studentshavecompletedthelist extends Component { }catch (e) { } + try { + if(this.props.Commonheadofthetestpaper.exercise_status !== undefined){ + this.setState({ + exercise_status:this.props.Commonheadofthetestpaper.exercise_status, + }) + }else{ + this.setState({ + exercise_status:0, + }) + } + }catch (e) { + + } + } componentWillReceiveProps = (nextProps) => { @@ -2007,11 +2080,11 @@ class Studentshavecompletedthelist extends Component { this.setState({ loadingstate: false, }) - console.log(response); - console.log(1997); + // console.log(response); + // console.log(1997); this.Generatenewdatasy(response.data.exercise_users, response); }).catch((error) => { - console.log(error) + // console.log(error) this.setState({ loadingstate: false, }) @@ -2414,7 +2487,7 @@ class Studentshavecompletedthelist extends Component { render() { const isAdmin = this.props.isAdmin(); - let {data, datas, page, columns, course_groupyslsthree, columnstwo, styletable, course_groupyslstwodatas, limit, course_groupysls, course_groupyslstwodata, course_groupyslstwo, teacherlists, Teacherliststudentlist, order, columnss, course_groupsdatas, course_groups, Evaluationarray, unlimited, unlimiteds, unlimitedtwo, teacherlist, searchtext, loadingstate, review, nocomment, commented, unsubmitted, submitted, columnsys, exercise_users,mylistansum} = this.state; + let {data, datas, page, columns, course_groupyslsthree, columnstwo, styletable,exercise_status, course_groupyslstwodatas, limit, course_groupysls, course_groupyslstwodata, course_groupyslstwo, teacherlists, Teacherliststudentlist, order, columnss, course_groupsdatas, course_groups, Evaluationarray, unlimited, unlimiteds, unlimitedtwo, teacherlist, searchtext, loadingstate, review, nocomment, commented, unsubmitted, submitted, columnsys, exercise_users,mylistansum} = this.state; // console.log("Studentshavecompletedthelist"); // console.log(this.props.current_status); return ( @@ -2425,202 +2498,211 @@ class Studentshavecompletedthelist extends Component { " min-width": " 1200px", }}> {/*老师*/} -
                  -
                    + { + exercise_status===0 || exercise_status===1 ? +
                    + +
                    + : +
                    +
                    +
                      - {/*你的评阅:*/} - { - Teacherliststudentlist === undefined || Teacherliststudentlist.exercise_types.subjective === 0 ? -
                    • - 作品状态: - this.notlimiteds()}>不限 - this.checkeboxstwo(e, course_groupyslstwodata && course_groupyslstwodata)}> - { - course_groupyslstwodata.map((item, key) => { - return ( - {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unanswer_users : Teacherliststudentlist.exercise_types.answer_users}) - ) - }) - } - -
                      - this.onSearchKeywordKeyUp(e)} - onInput={this.inputSearchValues} - onSearch={this.searchValues} - > -
                      -
                    • - : -
                      -
                    • - 你的评阅: - this.notlimited()}>不限 - - this.checkeboxs(e, course_groupyslstwodata && course_groupyslstwodata)}> - { - course_groupyslstwodatas.map((item, key) => { - return ( - {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unreview_counts : Teacherliststudentlist.exercise_types.review_counts}) - ) - }) - } - -
                      - this.onSearchKeywordKeyUp(e)} - onInput={this.inputSearchValues} - onSearch={this.searchValues} - > -
                      -
                    • - {/*作品状态*/} -
                    • - 作品状态: - this.notlimiteds()}>不限 - this.checkeboxstwo(e, course_groupyslstwodata && course_groupyslstwodata)}> - { - course_groupyslstwodata.map((item, key) => { - return ( - {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unanswer_users : Teacherliststudentlist.exercise_types.answer_users}) - ) - }) - } - -
                    • -
                      + {/*你的评阅:*/} + { + Teacherliststudentlist === undefined || Teacherliststudentlist.exercise_types.subjective === 0 ? +
                    • + 作品状态: + this.notlimiteds()}>不限 + this.checkeboxstwo(e, course_groupyslstwodata && course_groupyslstwodata)}> + { + course_groupyslstwodata.map((item, key) => { + return ( + {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unanswer_users : Teacherliststudentlist.exercise_types.answer_users}) + ) + }) + } + +
                      + this.onSearchKeywordKeyUp(e)} + onInput={this.inputSearchValues} + onSearch={this.searchValues} + > +
                      +
                    • + : +
                      +
                    • + 你的评阅: + this.notlimited()}>不限 + + this.checkeboxs(e, course_groupyslstwodata && course_groupyslstwodata)}> + { + course_groupyslstwodatas.map((item, key) => { + return ( + {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unreview_counts : Teacherliststudentlist.exercise_types.review_counts}) + ) + }) + } + +
                      + this.onSearchKeywordKeyUp(e)} + onInput={this.inputSearchValues} + onSearch={this.searchValues} + > +
                      +
                    • + {/*作品状态*/} +
                    • + 作品状态: + this.notlimiteds()}>不限 + this.checkeboxstwo(e, course_groupyslstwodata && course_groupyslstwodata)}> + { + course_groupyslstwodata.map((item, key) => { + return ( + {item.tu}({Teacherliststudentlist === undefined ? "0" : key === 0 ? Teacherliststudentlist.exercise_types.unanswer_users : Teacherliststudentlist.exercise_types.answer_users}) + ) + }) + } + +
                    • +
                      - } - {/*分班情况*/} - {course_groups === undefined ? "" : course_groups === null ? "" : course_groups.length < 2 ? "" : JSON.stringify(course_groups) === "[]" ? "" : -
                    • - - 分班情况: - this.funtaskstatustwos()}>不限 - - - this.funtaskstatustwo(e, course_groups && course_groups)} - style={{paddingTop: '4px', display: "inline"}}> - { - course_groups.map((item, key) => { - return ( - {item.exercise_group_name}({item.exercise_group_students}) - ) - }) - } - + } + {/*分班情况*/} + {course_groups === undefined ? "" : course_groups === null ? "" : course_groups.length < 2 ? "" : JSON.stringify(course_groups) === "[]" ? "" : +
                    • + + 分班情况: + this.funtaskstatustwos()}>不限 + + + this.funtaskstatustwo(e, course_groups && course_groups)} + style={{paddingTop: '4px', display: "inline"}}> + { + course_groups.map((item, key) => { + return ( + {item.exercise_group_name}({item.exercise_group_students}) + ) + }) + } + - - + + -
                    • - } + + } -
                    +
                  - - {JSON.stringify(data) !== "[]" ? -
                  - -
                  - {data === undefined ? "" : } - - +
                  + {data === undefined ? "" :
                  } + + - : -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  + : +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  -
                  - } +
                  + } - - { - Teacherliststudentlist && Teacherliststudentlist.exercise_types.total_users && Teacherliststudentlist.exercise_types.total_users > limit ? -
                  - +
                  + { + Teacherliststudentlist && Teacherliststudentlist.exercise_types.total_users && Teacherliststudentlist.exercise_types.total_users > limit ? +
                  + +
                  + : "" + } - : "" } @@ -2633,70 +2715,76 @@ class Studentshavecompletedthelist extends Component {
                  -
                  + { + exercise_status === 0 || exercise_status === 1 ? +
                  + +
                  + : +
                  -
                  +
                  -
                  +
                  {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} } -
                  +
                  -
                  +
                  - {JSON.stringify(datas) === "[]" ? -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  + {JSON.stringify(datas) === "[]" ? +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  -
                  - : -
                  - -
                  - {datas === undefined ? "" :
                  } - - - } - +
                  + {datas === undefined ? "" :
                  } + + + } - + + } @@ -2708,111 +2796,150 @@ class Studentshavecompletedthelist extends Component { "padding-bottom": "100px", " min-width": " 1200px" }}> -
                  -
                  - - {data === undefined ? "" :
                  } - - {JSON.stringify(datas) === "[]" ? - -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  - + { + exercise_status === 0 || exercise_status === 1 ? +
                  +
                  : -
                  - < div id="graduation_work_list" style={{ - padding: '0px 30px 10px 30px', - "margin-top": "20px", - "margin-bottom": "10px" - }}> +
                  +
                  + +
                  + {data === undefined ? "" :
                  } + + {JSON.stringify(datas) === "[]" ? -
                  +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  + +
                  + : +
                  + < div id="graduation_work_list" style={{ + padding: '0px 30px 10px 30px', + "margin-top": "20px", + "margin-bottom": "10px" + }}> + +
                  {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}} - -
                  - -
                  -
                  - -
                  - {datas === undefined ? "" :
                  } - +
                  + {datas === undefined ? "" :
                  } + - + - } - + } + - { - mylistansum && mylistansum > limit ? -
                  - + { + mylistansum && mylistansum > limit ? +
                  + +
                  + : "" + }
                  - : "" } diff --git a/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js b/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js index 2c56b8b58..ba3cee3d3 100644 --- a/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js +++ b/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js @@ -200,19 +200,20 @@ class Testpapersettinghomepage extends Component{ }) } }else { - 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(`正在下载中`); + 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{ 导出:""} @@ -434,7 +436,7 @@ class Testpapersettinghomepage extends Component{ /> { // 教师列表 - parseInt(tab[0])==0 && this.setcourse_groupysls(value)} current_status = {this.state.current_status}> + parseInt(tab[0])==0 && this.setcourse_groupysls(value)} current_status = {this.state.current_status} Commonheadofthetestpaper={this.state.Commonheadofthetestpaper}> } {/*统计结果*/} 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..1e2005360 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, @@ -181,6 +182,10 @@ class SingleEditor extends Component{ this.setState({ standard_answers }) } onOptionContentChange = (value, index) => { + if (index >= this.state.question_choices.length) { + // TODO 新建,然后删除CD选项,再输入题干,会调用到这里,且index是3 + return; + } let question_choices = this.state.question_choices.slice(0); question_choices[index] = value; this.setState({ question_choices }) 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..db4f89bfc 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,28 +214,55 @@ 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?:""}
                  { whethertoeditysl === false?
                  -
                  +
                  {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/gradinforms/Eduinforms.js b/public/react/src/modules/courses/gradinforms/Eduinforms.js index 14bcfa11a..38190afaf 100644 --- a/public/react/src/modules/courses/gradinforms/Eduinforms.js +++ b/public/react/src/modules/courses/gradinforms/Eduinforms.js @@ -25,16 +25,61 @@ class Eduinforms extends Component{ eduintits:"", informs:[], yslbool:false, + dataquerys:{}, } } componentDidMount() { + console.log("Eduinformss"); console.log("获取到数据"); - console.log(this.props); - - this.getinputdata(); + // console.log(this.props); + const query = this.props.location.search; + // const type = query.split('?chinaoocTimestamp='); + // console.log("Eduinforms12345"); + // console.log(this.foo(query)); + // console.log(JSON.stringify(this.foo(query))); + var dataqueryss={} + try { + var foqus=this.foo(query); + if(JSON.stringify(foqus) ==="{}"){ + this.setState({ + dataquerys:{}, + }); + }else { + this.setState({ + dataquerys:foqus, + }); + dataqueryss=foqus; + } + }catch (e) { + this.setState({ + dataquerys:{}, + }) + } + this.getinputdatas(dataqueryss); } + //截取数据 + foo=(url)=> { + var json = {}; + var regExp = /[\?\&](\w+)(=?)(\w*)/g; + var arr; + do { + arr = regExp.exec(url); + // console.log(arr); // arr = [完整的字符串, key, 等号或'', value或''] + + if (arr) { + var key = arr[1]; + var value = arr[3]; + // arr[2] === ''时, value = undefined + if (!arr[2]) + value = undefined; + + json[key] = value; + } + } while (arr); + return json; + } getyslbooltrue(){ console.log("调用了getyslbooltrue"); this.setState({ @@ -54,7 +99,47 @@ class Eduinforms extends Component{ }) let url = `/courses/${this.props.match.params.coursesId}/informs.json`; // - axios.get(url).then((response) => { + axios.get(url, + {params:this.state.dataquerys} + ).then((response) => { + if(response){ + if(response.data){ + this.setState({ + informs:response.data.informs, + isSpin:false, + }) + }else { + this.setState({ + informs:[], + isSpin:false, + + }) + + } + }else { + this.setState({ + informs:[], + isSpin:false, + }) + + } + }).catch((error) => { + console.log(error) + this.setState({ + informs:[], + isSpin:false, + }) + }); + } + getinputdatas=(yslwebobject)=>{ + this.setState({ + isSpin:true, + }) + let url = `/courses/${this.props.match.params.coursesId}/informs.json`; + // + axios.get(url, + {params:yslwebobject} + ).then((response) => { if(response){ if(response.data){ this.setState({ diff --git a/public/react/src/modules/courses/gradinforms/myysleduinforms.css b/public/react/src/modules/courses/gradinforms/myysleduinforms.css index b1efc783f..a05dc9a63 100644 --- a/public/react/src/modules/courses/gradinforms/myysleduinforms.css +++ b/public/react/src/modules/courses/gradinforms/myysleduinforms.css @@ -58,7 +58,7 @@ float: left; padding-top: 31px; padding-left: 25px; - font-size: 16px; + font-size: 21px; color: #05101A; text-align: left; font-weight:bold; @@ -70,6 +70,10 @@ .fudonyingxiangysl{ width: 100%; } +.fudonyingxiangysls{ + display: flex; + flex-direction:column; +} .yslbianji{ padding-top: 31px; diff --git a/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js b/public/react/src/modules/courses/graduation/tasks/GraduateTaskItem.js index 92a4832db..ef16e06a4 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}:"" } { @@ -249,7 +249,7 @@ class GraduateTaskItem extends Component{
                  -

                  +

                  {/* {discussMessage.author.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 b603e375d..7c697e31b 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){ @@ -116,50 +126,40 @@ class GraduationTasksSubmitedit extends Component{ this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } - if (info.file.status === 'done') { + if (info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } } - //onAttachmentRemove = (file) => { - - // confirm({ - // title: '确定要删除这个附件吗?', - // okText: '确定', - // cancelText: '取消', - // // content: 'Some descriptions', - // onOk: () => { - // this.deleteAttachment(file) - // }, - // onCancel() { - // console.log('Cancel'); - // }, - // }); - // return false; - - // this.setState({ - // Modalstype:true, - // Modalstopval:'确定要删除这个附件吗?', - // ModalSave: ()=>this.deleteAttachment(file), - // ModalCancel:this.cancelAttachment - // }) - // return false; - //} + onAttachmentRemove = (file) => { + if(!file.percent || file.percent == 100){ + this.setState({ + Modalstype:true, + Modalstopval:'确定要删除这个附件吗?', + ModalSave: ()=>this.deleteAttachment(file), + ModalCancel:this.cancelAttachment + }) + return false; + } + + } cancelAttachment=()=>{ this.setState({ Modalstype:false, - Modalstopval:'确定要删除这个附件吗?', + Modalstopval:'', ModalSave:"", ModalCancel:"" }) } - onAttachmentRemove = (file) => { - if(file.response!=undefined){ + + deleteAttachment = (file) => { + if(!file.percent || file.percent == 100){ let {attachments,fileList}=this.state; - const url = `/attachments/${file}.json` + let id=file.response ==undefined ? file.id : file.response.id; + const url = `/attachments/${id}.json` axios.delete(url, { }) .then((response) => { @@ -176,17 +176,15 @@ class GraduationTasksSubmitedit extends Component{ } } - - - this.setState({ - Modalstype:true, - Modalstopval:response.data.message, - ModalSave:this.cancelAttachment, - Loadtype:true, - attachments:newattachments - }) - - + // this.setState({ + // Modalstype:true, + // Modalstopval:response.data.message, + // ModalSave:this.cancelAttachment, + // Loadtype:true, + // attachments:newattachments + // }) + + this.cancelAttachment(); this.setState((state) => { const index = state.fileList.indexOf(file); const newFileList = state.fileList.slice(); @@ -287,7 +285,7 @@ class GraduationTasksSubmitedit extends Component{ let{ search,page,limit,workslist}=this.state; - let newpage=page+2 + let newpage=page+1 this.searchList(search,newpage,limit,workslist.task_id,1) @@ -391,7 +389,7 @@ class GraduationTasksSubmitedit extends Component{ let listid=[]; for(var list of fileList){ - listid.push(list.response.id) + listid.push(list.response == undefined ? list.id : list.response.id) } this.props.form.validateFields((err, values) => { @@ -498,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, @@ -572,17 +571,17 @@ class GraduationTasksSubmitedit extends Component{ {/*>*/} 毕设任务 > - 任务详情 + 任务详情 > {/**/} {/*{workslist&&workslist.task_name}*/} {/*>*/} {/**/} - {this.props.user&&this.props.user.username} 提交作品 + {this.props.current_user&&this.props.current_user.real_name} 修改作品

                  -

                  {workslist&&workslist.task_name}

                  +

                  { workslist && workslist.task_name }

                  返回
                  @@ -631,34 +630,34 @@ class GraduationTasksSubmitedit extends Component{ - {attachments&&attachments.map((item,key)=>{ - - return( -
                  - - - - - {item.title} - - - - {item.filesize} - - - {item.delete===true? - this.onAttachmentRemove(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 ? @@ -1149,7 +1008,7 @@ class GraduationTaskssettingapp extends Component{ } {/*内容*/} {task_type===2?
                  -
                  分组设置 (提交作品时需要关联同组成员,组内成员作品共享)
                  +
                  分组设置
                  ~ @@ -1175,7 +1034,7 @@ class GraduationTaskssettingapp extends Component{ -
                  +
                  发布时间: @@ -1213,7 +1072,7 @@ class GraduationTaskssettingapp extends Component{ {this.state.publishTimetypesval}
                  :""} -
                  +
                  截止时间: @@ -1306,17 +1165,12 @@ class GraduationTaskssettingapp extends Component{
                  - {/*
                  */} - {/*
                  项目质量检测
                  */} - - - {/*
                  */}
                  评分设置
                  最终成绩组成 (取各教师最终评分的平均分)
                  启用交叉评阅 (给老师分配其他指导老师的学生作品) + disabled={this.props.isAdmin()===true?flagPageEdit===true?commentstatustype===3?true:false:true:true} >启用交叉评阅 (给老师分配其他指导老师的学生作品) {crosscomment===true?
                  @@ -1437,14 +1291,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..0469d5d9c 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 ={ @@ -828,61 +850,47 @@ class GraduationTaskssettinglist extends Component{ ), }, { - title: '操作', - key: 'operation', - width:'100px', - dataIndex: 'operation', - className:'edu-txt-center', - render: operation => ( -
                  - {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} - + title: '操作', + key: 'operation', + width:'100px', + dataIndex: 'operation', + className:'edu-txt-center', + render: operation => ( +
                  + {this.props.isAdmin()?operation.map((tag,key) => { + return( + + { + tag.name && + 调整学生最终成绩
                  其它历史评分将全部失效:""}> + {tag.name==="评阅"? + {tag.name} + + : + this.showModulationtype(tag.id):tag.name==="分配"?()=>this.showAllocationModal(tag.id):""}> + {tag.name} + + } +
                  } +
                  + ) + }):""} + { + this.props.isStudent()? + operation.map((tag,key) => { + return( +
                  + {tag.view_work===false?"--":查看} +
                  + )} + ):"" + } +
                  -
                  -
                  - ) - }):""} - { - this.props.isStudent()? - operation.map((tag,key) => { - return( -
                  - {tag.view_work===false?"--":查看} -
                  - )} - ):"" - } -
                  - - ), - }]; + ), + }]; let courseId=this.props.match.params.coursesId; let position=this.props.match.params.position; @@ -950,6 +958,7 @@ class GraduationTaskssettinglist extends Component{ } + console.log(this.props.questionslist.status) return( @@ -963,10 +972,7 @@ class GraduationTaskssettinglist extends Component{ text-overflow: ellipsis; white-space: nowrap; } - .linbox{ - height: 26px; - } - .ant-table-tbody>tr>td, .ant-table-thead>tr>th{ + .ant-table-tbody>tr>td, .ant-table-thead>tr>th{ padding: 16px 10px } @@ -1090,99 +1096,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.questionslist&&this.props.questionslist.status===0?"":
                    • 教师评阅: @@ -1201,7 +1120,7 @@ class GraduationTaskssettinglist extends Component{ ) })} -
                      +
                      { return( - {item.name} - ({item.count}) - - + {item.name} + ({item.count}) + + ) })}
                    • } -
                    +
                  } -
                  + {this.props.questionslist&&this.props.questionslist.status===0?"":
                  {this.props.isAdmin()===true? {taskslistdata&&taskslistdata.work_count} - 个检索结果({taskslistdata&&taskslistdata.work_count} 学生) :""} + 个检索结果({taskslistdata&&taskslistdata.work_count} 学生):""} {this.props.isAdmin()===true? :""} -
                  +
                  } { JSON.stringify(data)==="[]" ? - -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  - -
                  + :
                  - + `} +
                  {data===undefined?"":
                  - - - - : + : // 学生列表 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 +1407,6 @@ class GraduationTaskssettinglist extends Component{
                      - {this.props.isAdmin()===true?
                      @@ -1576,8 +1428,6 @@ class GraduationTaskssettinglist extends Component{
                      :""} - - {this.props.isStudent()===true?
                      @@ -1595,12 +1445,7 @@ class GraduationTaskssettinglist extends Component{ }
                      :""} - - -
                  - - { JSON.stringify(data) === "[]" ? @@ -1652,12 +1497,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..ae764cc95 100644 --- a/public/react/src/modules/courses/graduation/tasks/index.js +++ b/public/react/src/modules/courses/graduation/tasks/index.js @@ -88,7 +88,7 @@ class GraduationTasks extends Component{ savedelete=()=>{ this.setState({ - Modalstype:false, + Modalstype:false, }) let {checkAllValue,checkBoxValues,search,page,order} = this.state; // let all_check; @@ -107,9 +107,10 @@ class GraduationTasks extends Component{ if (response.data.status == 0) { // {"status":1,"message":"删除成功"} this.fetchAll(search,page,order) + this.props.showNotification(response.data.message); this.setState({ - Modalstype:true, - Modalstopval:response.data.message, + // Modalstype:true, + // Modalstopval:response.data.message, ModalsBottomval:"", ModalSave:this.cancelmodel, Loadtype:true, @@ -469,7 +470,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 +568,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 511deb511..ba2ab53d9 100644 --- a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js +++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js @@ -11,7 +11,7 @@ import {getUrl} from 'educoder'; import "../../common/formCommon.css" import '../style.css' import '../../css/Courses.css' -import { WordsBtn, City } from 'educoder' +import { WordsBtn, City , getUploadActionUrl } from 'educoder' import {Link} from 'react-router-dom' // import City from './City' @@ -211,14 +211,16 @@ class GraduateTopicNew extends Component{ // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - this.setState({ fileList }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + this.setState({ fileList }); + } } onAttachmentRemove = (file) => { - if(file.response!=undefined){ - confirm({ - title: '确定要删除这个附件吗?', + if(!file.percent || file.percent == 100){ + this.props.confirm({ + content: '确定要删除这个附件吗?', okText: '确定', cancelText: '取消', // content: 'Some descriptions', @@ -307,7 +309,7 @@ class GraduateTopicNew extends Component{ // https://github.com/ant-design/ant-design/issues/15505 // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 // showUploadList: false, - action: `${getUrl()}/api/attachments.json`, + action: `${getUploadActionUrl()}`, onChange: this.handleChange, onRemove: this.onAttachmentRemove, beforeUpload: (file) => { @@ -447,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/graduation/topics/GraduateTopicPostWorksNew.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js index 3998669d7..38e68ad32 100644 --- a/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js +++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js @@ -159,11 +159,13 @@ class GraduateTopicPostWorksNew extends Component{ } // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - this.setState({ fileList }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + this.setState({ fileList }); + } } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ confirm({ title: '确定要删除这个附件吗?', okText: '确定', @@ -380,7 +382,7 @@ class GraduateTopicPostWorksNew extends Component{ )} - (项目管理员角色的成员都可以提交作品,提交作品时需要关联同组成员,组内成员作品共享) + (学生提交作品时需要关联同组成员,组内成员作品共享) 基于项目实施 )} - (勾选后各小组必须在educoder平台创建项目,教师可随时观察平台对各小组最小进展的实时统计) + (选中,则必须在本平台创建项目,项目管理员可以提交作品;不选中,无需在平台创建项目,任意小组成员均可以提交作品)
                  diff --git a/public/react/src/modules/courses/graduation/topics/index.js b/public/react/src/modules/courses/graduation/topics/index.js index b5be57564..ef4257e2e 100644 --- a/public/react/src/modules/courses/graduation/topics/index.js +++ b/public/react/src/modules/courses/graduation/topics/index.js @@ -58,7 +58,7 @@ class Boards extends Component{ let {pageSize}=this.state; const cid = this.props.match.params.coursesId - let url = `/courses/${cid}/graduation_topics.json?limit=`+pageSize + let url = `/courses/${cid}/graduation_topics.json?limit=${pageSize}` if(searchValue!=""){ url+="&search="+searchValue } @@ -68,7 +68,17 @@ class Boards extends Component{ if(status!="" && status != "all"){ url+="&status="+status; } - axios.get(url).then((response) => { + url=encodeURI(url);//IE11传参为乱码(search) + axios.get(url + // ,{ + // params:{ + // search:encodeURI(searchValue), + // page:page, + // status:status, + // limit:pageSize + // } + // } + ).then((response) => { if (response.status == 200 && response.status) { this.setState({ data:response.data, 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 de95bc741..ddd1164ea 100644 --- a/public/react/src/modules/courses/members/modal/AddStudentModal.js +++ b/public/react/src/modules/courses/members/modal/AddStudentModal.js @@ -29,7 +29,7 @@ class AddStudentModal extends Component{ const { name, school_name } = this.state let url = `/courses/${courseId}/search_users.json?page=${page}&limit=${pageCount}&school_name=${school_name || ''}&name=${name || ''}` this.setState({ loading: true }) - axios.get(url) + axios.get(encodeURI(url)) .then((response) => { if (!response.data.users || response.data.users.length == 0) { this.setState({ @@ -80,14 +80,18 @@ class AddStudentModal extends Component{ } setVisible = (visible) => { if (visible) { - this.setState({school_name: this.props.user.user_school}) - this.fetchMemberList() + this.setState({ + school_name: this.props.user.user_school, + name: undefined + },()=>{ + this.fetchMemberList(); + }) this.fetchOptions() } this.refs.modalWrapper.setVisible(visible) if (visible == false) { this.setState({ - checkBoxValues: [] + checkBoxValues: [], }) } } @@ -212,18 +216,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/modal/CreateGroupByImportModal.js b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js index 77a41e47d..afbe8de58 100644 --- a/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js +++ b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js @@ -73,7 +73,7 @@ class CreateGroupByImportModal extends Component{ } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.props.confirm({ content: '是否确认删除?', diff --git a/public/react/src/modules/courses/members/studentsList.js b/public/react/src/modules/courses/members/studentsList.js index 08f4971ce..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,12 +327,23 @@ 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; } - axios.get((url)).then((result)=>{ + axios.get(encodeURI(url)).then((result)=>{ if (result.data.students) { this.setState({ students: result.data.students, @@ -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,9 +513,19 @@ 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() + const isCourseEnd = this.props.isCourseEnd() let { page, @@ -591,7 +620,7 @@ class studentsList extends Component{ > this.refs['createGroupByImportModal'].setVisible(true)}>导入创建分班 } - { isAdmin && isParent && this.addDir()}>添加分班 } + { !isCourseEnd && isAdmin && isParent && this.addDir()}>添加分班 } { isAdmin && !isParent && course_group_id != 0 && this.deleteDir()}>删除分班 } { isAdmin && !isParent && course_group_id != 0 && this.renameDir()}>分班重命名 } 问卷须知
                  */} + { + 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()}>主观题 +
                  +
                  + :
                  } +
                  +
                  + + {/**/} +
                  +
                  +
                  + ) + } + +} + +// 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 64e2e6a99..93ed7ff7d 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -33,6 +33,8 @@ import Startshixuntask from "../coursesPublic/Startshixuntask"; import ModulationModal from "../coursesPublic/ModulationModal"; import HomeworkModal from "../coursesPublic/HomeworkModal"; import ShixunWorkModal from "./Shixunworkdetails/ShixunWorkModal"; +import NoneData from '../../../modules/courses/coursesPublic/NoneData' + const Search = Input.Search; const RadioGroup = Radio.Group; const CheckboxGroup = Checkbox.Group; @@ -67,7 +69,7 @@ class Listofworksstudentone extends Component { pages: 1, limit: 20, loadingstate: true, - order: "update_time", + order: "", search: null, day: 0, hour: 0, @@ -93,27 +95,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 +131,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 +178,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 +228,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 +269,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 +291,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 +703,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 +730,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 +766,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 +799,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 +822,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 +840,7 @@ class Listofworksstudentone extends Component { align: 'center', className:'font-14', render: (text, record) => ( - {record.number} + {record.number} ) }, @@ -425,7 +852,7 @@ class Listofworksstudentone extends Component { className:'font-14 maxnamewidth100', width:'100px', render: (text, record) => ( - {record.name} + {record.name} ) }, { @@ -434,25 +861,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 +886,8 @@ class Listofworksstudentone extends Component { title={record.stduynumber} className="maxnamewidth110" style={{ - "color": '#9A9A9A', - "text-align": "center" + color: '#9A9A9A', + textAlign: "center" }}>{ record.stduynumber } @@ -480,7 +906,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 +918,11 @@ class Listofworksstudentone extends Component { className:'font-14', render: (text, record) => ( {record.submitstate} ) @@ -511,24 +937,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 +987,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 +1002,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 +1048,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 +1080,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 +1108,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 +1153,7 @@ class Listofworksstudentone extends Component { align: 'center', className:'font-14', render: (text, record) => ( - {record.number} + {record.number} ) }, @@ -719,7 +1165,7 @@ class Listofworksstudentone extends Component { className:'font-14 maxnamewidth100', width:'100px', render: (text, record) => ( - {record.name} + {record.name} ) }, { @@ -728,24 +1174,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 +1199,8 @@ class Listofworksstudentone extends Component { title={record.stduynumber} className="maxnamewidth110" style={{ - "color": '#9A9A9A', - "text-align": "center" + color: '#9A9A9A', + textAlign: "center" }}>{ record.stduynumber } @@ -774,7 +1219,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 +1231,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 +1260,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 +1293,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 +1308,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 +1354,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 +1386,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 +1414,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} } @@ -995,17 +1453,14 @@ class Listofworksstudentone extends Component { ], yslpros:false, datajs:[], + homework_status:[], } - // console.log("902"); - // console.log("902"); - // console.log(this.props); - } componentDidCatch(error, info){ - console.log("-----------------------------905错误信息"); - console.log(error); - console.log(info); + // console.log("-----------------------------905错误信息"); + // console.log(error); + // console.log(info); } // componentWillReceiveProps(nextProps) { @@ -1037,6 +1492,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 +1537,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____________________"); @@ -1112,7 +1572,8 @@ class Listofworksstudentone extends Component { allow_late:result.data.allow_late, loadingstate: false, computeTimetype:true, - }) + homework_status:result.data.homework_status, + }); this.seacthdatat(result.data,result.data.student_works,result.data.work_efficiency,result.data.course_group_info,1); if (result.data.student_works === undefined || result.data.student_works === null || JSON.stringify(result.data.student_works) === "[]") { @@ -1169,7 +1630,8 @@ class Listofworksstudentone extends Component { code_review: result.data.code_review, challenges_count:result.data.challenges_count, view_report:result.data.view_report, - }) + homework_status:result.data.homework_status, + }); if (result.data.student_works === undefined || result.data.student_works === null || JSON.stringify(result.data.student_works) === "[]") { this.seacthdata(result.data); } else { @@ -1201,6 +1663,7 @@ class Listofworksstudentone extends Component { let datalists = []; var styletable = {"display": "none"} var arr =[]; + var arr2=[]; for(var i=0;i { // console.log("viewtraining") @@ -1580,7 +2134,8 @@ class Listofworksstudentone extends Component { code_review: result.data.code_review, challenges_count:result.data.challenges_count, view_report:result.data.view_report, - }) + homework_status:result.data.homework_status, + }); this.seacthdata(result.data); this.props.Getdataback(result,result.data); } @@ -1654,9 +2209,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 @@ -1693,7 +2248,8 @@ class Listofworksstudentone extends Component { end_immediately: result.data.end_immediately, code_review: result.data.code_review, challenges_count:result.data.challenges_count, - }) + homework_status:result.data.homework_status, + }); this.seacthdatat(result.data,result.data.student_works,result.data.work_efficiency,result.data.course_group_info,page); this.props.Getdataback(result,result.data); // } @@ -2063,15 +2619,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 +2660,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 +3027,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 +3044,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,homework_status, 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); @@ -2499,90 +3057,118 @@ class Listofworksstudentone extends Component { // console.log(data); // console.log(datas); // 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 ? - ( -
                  - {visible === true ? this.saveModulationModal(value, num)} - /> : ""} - - {this.state.showmodel === true ? this.hideshowmodel()} - updatas={() => this.isupdatas()} - /> : ""} - - - {visibles === true ? -
                  - - this.cancelModulationModels()} - /> - -
                  - : "" - } - - {/*立即发布*/} - this.getcourse_groupslist(id)} - starttimes={this.state.starttimes} - typs={this.state.typs} - /> -
                  - - -
                  - - - + this.cancelModulationModels()} + /> + +
                  + : "" + } + + {/*立即发布*/} + this.getcourse_groupslist(id)} + starttimes={this.state.starttimes} + typs={this.state.typs} + /> + { + homework_status&&homework_status.length===0? +
                  + +
                  + : + homework_status&&homework_status.length>0 && homework_status[0]==="未发布"? +
                  + +
                  + : +
                  + + +
                  + + + - {computeTimetype===false?
                • - - + + {computeTimetype===false?
                • + + 正在执行成绩计算,完成后将为您自动刷新结果。温馨提示:执行时间因作品数量而异 -
                • :""} - - {/*作品状态GraduationTaskssettinglist*/} -
                    -
                  • - 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} - - {teacherdata&&teacherdata.publish_immediately===false&&computeTimetype===true? - (this.props.isNotMember()===false?
                    - 计算成绩 -
                    :""): - teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": - (this.props.isNotMember()===false?
                    - 计算成绩 -
                    :"") - } -
                    - -
                    +
                  • :""} + + {/*作品状态GraduationTaskssettinglist*/} +
                      +
                    • + 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} + + +
                      + {course_is_end===true?"": + {teacherdata&&teacherdata.update_score===true&&computeTimetype===true? + (this.props.isNotMember()===false?
                      + 查看最新成绩 +
                      :""): + teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": + (this.props.isNotMember()===false?
                      + 查看最新成绩 +
                      :"") + } +
                      } + -
                      -
                    • - -
                    • - - 作品状态: - this.notlimiteds()}>不限 - this.funtaskstatust(e, task_status && task_status)} - style={{paddingTop: '4px'}}> - - {task_status === undefined ? "" : task_status.map((item, key) => { - return ( - + +
                  + + +
                • + + 作品状态: + this.notlimiteds()}>不限 + this.funtaskstatust(e, task_status && task_status)} + style={{paddingTop: '4px'}}> + + {task_status === undefined ? "" : task_status.map((item, key) => { + return ( + {item.name} @@ -2684,96 +3275,96 @@ class Listofworksstudentone extends Component { - ) - })} - - {/*请输入姓名或学号搜索*/} - - -
                • - - - {/*分班情况*/} - -
                • - {JSON.stringify(course_group_info) === "[]" ? "" : course_group_info === undefined ? "" : course_group_info.length < 2 ? "" : -
                  - 分班情况: - this.notlimitedst()}>不限 - this.funtaskstatustwot(e, course_group_info && course_group_info)} - style={{paddingTop: '4px',width:'1017px'}}> - {course_group_info === undefined ? "" : - course_group_info.map((item, key) => { - return ( - + ) + })} + + {/*请输入姓名或学号搜索*/} + + +
                • + + + {/*分班情况*/} + +
                • + {JSON.stringify(course_group_info) === "[]" ? "" : course_group_info === undefined ? "" : course_group_info.length < 2 ? "" : +
                  + 分班情况: + this.notlimitedst()}>不限 + this.funtaskstatustwot(e, course_group_info && course_group_info)} + style={{paddingTop: '4px',width:'1017px'}}> + {course_group_info === undefined ? "" : + course_group_info.map((item, key) => { + return ( + {item.group_group_name} ({item.count}) - ) - }) - } - -
                  } -
                • + ) + }) + } + +
                  } + - + -
                  + + { + JSON.stringify(datajs) === "[]" ? + +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  + +
                  + : + +
                  + -
                  - {datajs === undefined ? "" :
                  } - - - } - - - - { - teacherdata && teacherdata.work_count && teacherdata.work_count > limit ? -
                  - -
                  - : "" - } - - - - ) +
                  + {datajs === undefined ? "" :
                  } + + + } + + + + { + teacherdata && teacherdata.work_count && teacherdata.work_count > limit ? +
                  + +
                  + : "" + } + + } + : - ( -
                  - { - teacherdata === undefined || teacherdata.student_works === undefined || teacherdata.student_works === null || JSON.stringify(teacherdata.student_works) === "[]" ? - // 学生不能查看别人的 -
                  - - {visibles === true ? -
                  - - + {visibles === true ? +
                  + + - this.cancelModulationModels()} - /> -
                  - : "" - } + } + + this.cancelModulationModels()} + /> +
                  + : "" + } + + { + homework_status&&homework_status.length&&homework_status.length===0? +
                  + +
                  + : + homework_status&&homework_status.length>0 && homework_status&&homework_status[0]==="未发布"? +
                  + +
                  + : -
                  -
                  - - {computeTimetype===false?
                • - - + + {computeTimetype===false?
                • + + 正在执行成绩计算,完成后将为您自动刷新结果。温馨提示:执行时间因作品数量而异 -
                • :""} + :""} - {JSON.stringify(data) !== "[]" ? -
                  -
                  + {JSON.stringify(data) !== "[]" ? +
                  +
                  -
                  +
                  -
                  +
                  - 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} - {teacherdata&&teacherdata.task_operation[0]==="开启挑战"?"": + 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} + { course_is_end===true?"":teacherdata&&teacherdata.task_operation[0]==="开启挑战"?"": {computeTimetype===true? (this.props.isNotMember()===false? -
                  - 计算成绩 -
                  + ( + teacherdata&&teacherdata.update_score===true? +
                  + 查看最新成绩 +
                  + :"" + ) :"") : (teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": this.props.isNotMember()===false? -
                  - 计算成绩 +
                  + 查看最新成绩
                  :"") } } -
                  +
                  -
                  +
                  -
                  -
                  - -
                  - {data === undefined ? "" :
                  } - - - +
                  + {data === undefined ? "" :
                  } + + + - : -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  + : +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  -
                  - } +
                  + } - + - + + } + + : + // 学生能查看别人的 +
                  + {/*双层*/} + + + {visibles === true ? + this.cancelModulationModels()} + /> : "" + } -
                  - : - // 学生能查看别人的 -
                  - - - {visibles === true ? - this.cancelModulationModels()} - /> : "" - } -
                  + { + homework_status&&homework_status.length===0? +
                  + +
                  + : + homework_status&&homework_status.length>0 && homework_status&&homework_status[0]==="未发布"? +
                  + +
                  + : +
                  -
                  - + - {computeTimetype===false?
                • - - + {computeTimetype===false?
                • + + 正在执行成绩计算,完成后将为您自动刷新结果。温馨提示:执行时间因作品数量而异 -
                • :""} + :""} - -
                  - {data === undefined ? "" :
                  } - - {JSON.stringify(datas) !== "[]" ? -
                  -
                  -
                  + } + +
                  + {data === undefined ? "" :
                  } + + {JSON.stringify(datas) !== "[]" ? +
                  +
                  +
                  {teacherdata === undefined ? "0" : teacherdata.commit_count === undefined ? "0" : teacherdata.commit_count} @@ -3109,8 +3738,8 @@ class Listofworksstudentone extends Component { style={{color: '#FF6800'}}>{teacherdata.left_time.time}} - -
                  - - 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} - {teacherdata&&teacherdata.task_operation&&teacherdata.task_operation[0]==="开启挑战"?"": - {computeTimetype===true? - (this.props.isNotMember()===false?
                  - 计算成绩 -
                  :""): - teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": - (this.props.isNotMember()===false?
                  - 计算成绩 -
                  :"") - } -
                  } - -
                  - {/*因为计算按钮占了和这个位置,和设计沟通学生视角取消这个按钮*/} - {/**/} - -
                  - -
                  - -
                  - +
                  + + 计算成绩时间:{teacherdata&&teacherdata.calculation_time==null?"--": moment(teacherdata&&teacherdata.calculation_time).format('YYYY-MM-DD HH:mm')} + { course_is_end===true?"":teacherdata&&teacherdata.task_operation&&teacherdata.task_operation[0]==="开启挑战"?"": + {computeTimetype===true? + + (this.props.isNotMember()===false? + ( + teacherdata&&teacherdata.update_score===true? +
                  + 查看最新成绩 +
                  :"" + ) + :""): + teacherdata&&teacherdata.homework_status!==undefined&&teacherdata.homework_status[0]=== "未发布"? "": + (this.props.isNotMember()===false?
                  + 查看最新成绩 +
                  :"") + } +
                  } +
                  +
                  +
                  +
                  + -
                  - {datas === undefined ? "" :
                  } +
                  + {datas === undefined ? "" :
                  } + + + { + teacherdata && teacherdata.work_count && teacherdata.work_count > limit ? +
                  + +
                  + : "" + } + + : +
                  +
                  +
                  + +

                  暂时还没有相关数据哦!

                  +
                  +
                  +
                  + } - - { - teacherdata && teacherdata.work_count && teacherdata.work_count > limit ? -
                  - -
                  - : "" } - : -
                  -
                  -
                  - -

                  暂时还没有相关数据哦!

                  -
                  -
                  - -
                  - } - - - {/*///*/} - - - - - - } - ) + ) } } -export default Listofworksstudentone; -{/*
                  */} -{/*
                  */} -{/* this.ChangeTab(0)}>作品列表*/} -{/* this.ChangeTab(1)}>作业问答*/} -{/* this.ChangeTab(3)}*/} -{/* >设置*/} -{/* {this.state.view_report===true?*/} -{/* 查看实训报告*/} -{/* :""}*/} -{/* /!*查看实训报告*!/*/} -{/* {*/} -{/* teacherdata === undefined ? ""*/} -{/* : teacherdata.commit_des === null || teacherdata.commit_des === undefined ? "" :*/} -{/* {teacherdata.commit_des}*/} -{/* }*/} -{/* {teacherdata === undefined ? "" : }*/} -{/*
                  */} -{/*
                  */} -{/*
                  */} -{/*
                  */} -{/* this.ChangeTab(0)}>作品列表*/} -{/* this.ChangeTab(1)}>作业问答*/} -{/* this.ChangeTab(3)}>设置*/} -{/* {this.state.view_report===true?*/} -{/* 查看实训报告*/} -{/* :""}*/} -{/* {*/} -{/* teacherdata === undefined ? ""*/} -{/* : teacherdata.commit_des === null || teacherdata.commit_des === undefined ? "" :*/} -{/* {teacherdata.commit_des}*/} -{/* }*/} -{/* {teacherdata === undefined ? "" : }*/} -{/*
                  */} -{/*
                  */} \ No newline at end of file +export default Listofworksstudentone; \ No newline at end of file diff --git a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js index 4f403205d..bb96b7cdf 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunHomeworkPage.js @@ -3,7 +3,8 @@ import {Link, NavLink} from 'react-router-dom'; import {WordsBtn, ActionBtn} from 'educoder'; import axios from 'axios'; import { - notification + notification, + Spin } from "antd"; import '../css/members.css'; import "../common/formCommon.css"; @@ -20,6 +21,7 @@ import Startshixuntask from "../coursesPublic/Startshixuntask"; import TPMMDEditor from "../../tpm/challengesnew/TPMMDEditor"; import DownloadMessageysl from "../../modals/DownloadMessageysl"; +import Modals from "../../modals/Modals"; class ShixunHomeworkPage extends Component { constructor(props) { super(props); @@ -34,6 +36,10 @@ class ShixunHomeworkPage extends Component { showmodel:false, child:undefined, yslpros:false, + Modalstopval:"你在该实训的学习记录将被清空,无法恢复", + ModalsBottomval:"是否确认重做?", + ModalsType:false, + mylistisSpin:false, } } @@ -107,9 +113,61 @@ class ShixunHomeworkPage extends Component { workshowmodels(child){ child.workshowmodel(); } - /// 确认是否下载 + /// 重做的确认 + ModalSaves=()=>{ + + this.setState({ + ModalsType:false, + Modalstopval:"" + }); + if(this.state.teacherdatapage){ + this.resetshixunCombat(this.state.teacherdatapage.myshixun_identifier); + } + try { + console.log("this.child"); + console.log(this.child); + }catch (e) { + } + }; + //取消重做 + ModalCancels=()=>{ + this.setState({ + ModalsType:false, + Modalstopval:"" + }) + }; + //打开重做弹框 + Modalcancelss=()=>{ + this.setState({ + Modalstopval:"你在该实训的学习记录将被清空,无法恢复", + ModalsBottomval:"是否确认重做?", + ModalsType:true, + }) + } + //重置按钮 + resetshixunCombat=(id)=>{ + this.setState({ + mylistisSpin:true, + }) + let zrl=`/myshixuns/${id}/reset_my_game.json`; + axios.get(zrl).then((response) => { + // window.location.href = "/shixuns/" + response.data.shixun_identifier + "/challenges"; + this.setState({ + mylistisSpin:false, + }) + this.child.Isupdatass(); + this.props.showNotification("已清空本实训的学习记录\n" + + "\n" + + "请点击“开启挑战”重做实训作业"); + }).catch((error) => { + this.setState({ + mylistisSpin:false, + }) + console.log(error) + }); + } bindRef = ref => { this.child = ref } ///////////////教师截止 gotohome=()=>{ @@ -128,10 +186,17 @@ class ShixunHomeworkPage extends Component { return (
                  - - + +
                  - +

                  {jobsettingsdatapage === undefined ? "" : jobsettingsdatapage.data.course_name} @@ -157,7 +222,6 @@ class ShixunHomeworkPage extends Component {

                  -
                  @@ -251,23 +315,27 @@ class ShixunHomeworkPage extends Component { {...this.props} data={teacherdatapage} />} + {this.props.isStudent() ? + ( + teacherdatapage&&teacherdatapage.redo_work===true? + this.Modalcancelss()}>重做 + :"" + ) + : "" }
                  - {/**/} - {parseInt(tab) === 0 ? this.Getdataback(jobsettingsdata, teacherdata)}>:""} {parseInt(tab) === 1 ? this.Getdataback(jobsettingsdata, teacherdata)}>:""} {parseInt(tab) === 2 ? this.Getdataback(jobsettingsdata, teacherdata)}>:""} {parseInt(tab) === 3 ? this.Getdataback(jobsettingsdata, teacherdata)}>:""} - +
                  ) diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js index 967a6ca61..8254b148e 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkDetails.js @@ -35,10 +35,15 @@ class ShixunWorkDetails extends Component { } }).then((result) => { if (result.status === 200) { - this.setState({ - data:result.data, - spinning:false - }) + if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) { + + }else{ + this.setState({ + data:result.data, + spinning:false + }) + } + } }).catch((error) => { console.log(error) @@ -50,7 +55,33 @@ class ShixunWorkDetails extends Component { shixuntypes:type[3] }) } + updatas=()=>{ + this.setState({ + spinning:true + }) + let homeworkid=this.props.match.params.homeworkid; + let userid=this.props.match.params.userid; + let url = "/homework_commons/"+homeworkid+"/code_review_detail.json"; + axios.get(url,{ + params: { + user_id:userid, + } + }).then((result) => { + if (result.status === 200) { + if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) { + }else{ + this.setState({ + data:result.data, + spinning:false + }) + } + + } + }).catch((error) => { + console.log(error) + }) + } goback=(sum)=>{ // let{data}=this.state // if(sum===1){ @@ -102,14 +133,18 @@ class ShixunWorkDetails extends Component { 非编程类型任务,不参与查重 被查作品: - {data&&data.username} - {data&&data.final_score}分 + {data&&data.username} + {data&&data.eff_score===null||data&&data.eff_score===undefined||data&&data.eff_score_full===null||data&&data.eff_score_full===undefined?"":效率分:{data&&data.eff_score}/{data&&data.eff_score_full}} + 最终成绩:{data&&data.final_score}
                  this.updatas()} data={data} />
                  diff --git a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js index 434101f33..2667f1dd9 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunWorkReport.js @@ -1,14 +1,17 @@ import React, {Component} from "react"; -import {WordsBtn,markdownToHTML,ActionBtn,queryString,downloadFile} from 'educoder'; +import {WordsBtn,markdownToHTML,ActionBtn,queryString,downloadFile,getImageUrl} from 'educoder'; import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider,InputNumber, Tag,DatePicker,Radio,Tooltip,Spin} from "antd"; import {Link,Switch,Route,Redirect} from 'react-router-dom'; import axios from 'axios'; - +import moment from 'moment'; +import Modals from "../../modals/Modals"; import ConclusionEvaluation from './shixunreport/ConclusionEvaluation'; import OfficialAcademicTranscript from './shixunreport/OfficialAcademicTranscript'; import Coursesshixundetails from './shixunreport/Coursesshixundetails'; import Shixunechart from './shixunreport/Shixunechart'; -import DownloadMessageysl from "../../modals/DownloadMessageysl"; +import DownloadMessageysl from "../../modals/DownloadMessageysl" +import AppraiseModal from "../coursesPublic/AppraiseModal"; +import ShowAppraiseList from './ShowAppraiseList'; import {UnControlled as CodeMirror} from 'react-codemirror2'; import 'codemirror/mode/cmake/cmake'; import 'codemirror/mode/xml/xml'; @@ -20,6 +23,7 @@ import '../css/Courses.css'; import './style.css'; import 'moment/locale/zh-cn'; + class ShixunWorkReport extends Component { constructor(props) { @@ -29,7 +33,10 @@ class ShixunWorkReport extends Component { spinning:true, DownloadType:false, DownloadMessageval:undefined, - isspinning:false + isspinning:false, + showAppraiseModaltype:false, + work_comment_hidden:undefined, + work_comment:undefined, } } @@ -41,8 +48,7 @@ class ShixunWorkReport extends Component { if(child!=undefined){ params =child._getRequestParams()!==undefined?child._getRequestParams():{}; } - console.log("170"); - console.log(params); + const urll=url+`?${queryString.stringify(params)}`; axios.get(urll+ '&export=true').then((response) => { if(response===undefined){ @@ -72,6 +78,7 @@ class ShixunWorkReport extends Component { } }).catch((error) => { console.log(error) + this.setState({ isspinning: false }) }); } Downloadcal=()=>{ @@ -95,11 +102,13 @@ class ShixunWorkReport extends Component { let homeworkid=this.props.match.params.homeworkid; let url = `/student_works/${homeworkid}/shixun_work_report.json` axios.get(url).then((result) => { - if (result.data.status === 403||result.data.status === 401||result.data.status === 407||result.data.status === 408) { + if (result.data.status === 403 || result.data.status === 401 || result.data.status === 407 || result.data.status === 408|| result.data.status === 409 || result.data.status === 500) { }else{ this.setState({ data:result.data, + work_comment_hidden:result.data.work_comment_hidden, + work_comment:result.data.work_comment, spinning:false }) } @@ -145,17 +154,188 @@ class ShixunWorkReport extends Component { data:newdata }) } + + showAppraiseModal=(type,id,show,hidden)=>{ + let{data}=this.state; + + if(type==="child"){ + data.stage_list.forEach((item,key)=>{ + if(item.challenge_id===id){ + item.challenge_comment=show; + item.challenge_comment_hidden=hidden; + } + }) + this.setState({ + showAppraiseModaltype:true, + showAppraisetype:type, + challenge_id:id, + data:data + }) + }else{ + this.setState({ + showAppraiseModaltype:true, + showAppraisetype:type, + challenge_id:undefined, + work_comment:show, + work_comment_hidden:hidden + }) + } + + } + + hideAppraiseModal=()=>{ + this.setState({ + showAppraiseModaltype:false, + }) + } + showAppraiseModals=(show,hidden,id,comment_id)=>{ + + let{data,showAppraisetype}=this.state; + + if(showAppraisetype==="child"){ + data.stage_list.forEach((item,key)=>{ + if(item.challenge_id===id){ + item.challenge_comment=show; + item.challenge_comment_hidden=hidden; + item.comment_id=comment_id + } + }) + this.setState({ + showAppraiseModaltype:false, + data:data + }) + }else{ + data.comment_id=comment_id; + this.setState({ + showAppraiseModaltype:false, + work_comment:show, + work_comment_hidden:hidden, + data:data + }) + } + + } + isdeleteModal=(comment_id,visible_comment,type)=>{ + let newcomment_id=comment_id; + let newvisible_comment=visible_comment; + let newtype=type; + this.setState({ + modalsType: true, + modalsTopval:"是否确认删除?", + modalSave: ()=>this.isdeleteModals(newcomment_id,newvisible_comment,newtype), + modalCancel:()=>this.hideisdeleteModals(), + }) + } + + hideisdeleteModals=()=>{ + this.setState({ + modalsType:false, + modalsTopval:"是否确认删除?", + modalSave: "", + modalCancel:"", + }) + } + + + hideisdeleteModal=(comment_id,visible_comment,type)=>{ + + + let{data,work_comment,work_comment_hidden}=this.state; + + if(type==="child"){ + data.stage_list.map((item,key)=>{ + console.log(item) + if(item.comment_id!=null){ + if(item.comment_id===comment_id){ + item.challenge_comment=null; + item.challenge_comment_hidden=null; + } + } + }) + + this.setState({ + modalsType:false, + modalsTopval:"是否确认删除?", + modalSave: "", + modalCancel:"", + data:data + }) + + }else{ + + this.setState({ + modalsType:false, + modalsTopval:"是否确认删除?", + modalSave: "", + modalCancel:"", + work_comment:null, + work_comment_hidden:null + }) + + + } + + } + + isdeleteModals=(comment_id,visible_comment,type)=>{ + let newcomment_id=comment_id; + let newvisible_comment=visible_comment; + let newtype=type; + if(comment_id!=null){ + let url =`/student_works/${this.props.match.params.homeworkid}/destroy_work_comment.json` + axios.delete(url, { data: { + comment_id:comment_id, + }}).then((response) => { + // const { status } = response.data; + if(response.data.status===0){ + this.props.showNotification(response.data.message) + this.hideisdeleteModal(newcomment_id,newvisible_comment,newtype) + }else{ + this.props.showNotification(response.data.message) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + } render() { - let{data} =this.state; - console.log(data) - console.log(this.props) + let{data,showAppraiseModaltype,work_comment_hidden,work_comment} =this.state; + let category_id=data===undefined?"":data.category===null?"":data.category.category_id; let homework_common_id=data===undefined?"":data.homework_common_id; let homeworkid=this.props.match.params.homeworkid; const antIcon = ; + + // let showAppraiseModals=this.props&&this.props.isAdminOrTeacher()===true?work_comment===null||work_comment===undefined?false:true:work_comment===null||work_comment===undefined?false:true; + let showAppraiseModals=work_comment===null||work_comment===undefined?false:true; + return ( - data===undefined?"":
                  + data===undefined?"": + + + + + {showAppraiseModaltype===true?this.hideAppraiseModal()} + showCancel={(show,hidden,id,comment_id)=>this.showAppraiseModals(show,hidden,id,comment_id)} + work_comment={this.state.work_comment} + work_type={work_comment===null||work_comment===undefined?this.state.work_type:work_comment_hidden===true?1:0} + />:""} + + +
                  {data&&data.course_name} > - + {data===undefined?"":data.category===null?"":data.category.category_name} > @@ -181,18 +361,123 @@ class ShixunWorkReport extends Component {

                  {data&&data.shixun_name}

                  {/*{this.props.isAdmin()?导出实训报告数据:""}*/} - 返回 + 返回 {this.props.isAdmin() ? this.confirmysl(`/student_works/${homeworkid}/export_shixun_work_report.pdf`)} > 导出实训报告数据 : ""} + {/*{this.props.isAdmin() ?work_comment_hidden===true? "":this.showAppraiseModal(1)}*/} + {/*>评阅 : ""}*/} + {this.props.isAdmin() ?this.showAppraiseModal("main",undefined,work_comment,work_comment_hidden)} + >评阅:""}
                  + + {/*{work_comment===null||work_comment===undefined?"评阅":"编辑评阅"}*/} +
                  -
                  总体评价
                  +
                  总体评价
                  +
                  +
                  + +
                  + +
                  + +
                  +

                  {data&&data.username}

                  + +

                  + +

                  通过关卡: {data&&data.complete_count}/{data&&data.challenges_count}
                  +
                  经验值: {data&&data.myself_experience}/{data&&data.total_experience}
                  + + +
                  课堂最高完成效率: {data&&data.max_efficiency===null?'--':data&&data.max_efficiency}
                  +
                  完成效率: {data&&data.efficiency===null?'--':data&&data.efficiency}
                  +
                  + + +
                  通关时间: {data&&data.passed_time===null||data&&data.passed_time=== "--"?'--':moment(data&&data.passed_time).format('YYYY-MM-DD HH:mm')}
                  +
                  实战耗时: {data&&data.time_consuming===null?'--':data&&data.time_consuming}
                  +
                  +

                  + +
                  + +
                  +
                  @@ -200,7 +485,7 @@ class ShixunWorkReport extends Component {
                  -
                  +
                  阶段成绩
                  @@ -211,20 +496,16 @@ class ShixunWorkReport extends Component { jumptopic={this.jumptopic} getdatalist={()=>this.getdatalist()} setupdalist={(challenge_score,overall_appraisal,work_score)=>this.setupdalist(challenge_score,overall_appraisal,work_score)} + showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)} />
                  -
                  -
                  -
                  个人总结
                  - -
                  -
                  + -
                  +
                  +
                  +
                  + 个人总结 +
                  +
                  +
                  +
                  +
                  +
                  -
                  + + this.isdeleteModal(comment_id,visible_comment,type)} + showAppraiseModal={(type,id,show,hidden)=>this.showAppraiseModal(type,id,show,hidden)} + /> + + +
                  图形统计
                  -

                  - +

                  + {/* {discussMessage.author.name} */} { discussMessage.author && {discussMessage.author} } {discussMessage.commit_count===undefined?"":{discussMessage.commit_count} 已交} @@ -357,6 +357,15 @@ class ShixunhomeWorkItem extends Component{ : {discussMessage.status_time} } + { + discussMessage && discussMessage.upper_category_name && + 22 }> + { {discussMessage.upper_category_name}} + + } + + + {/* { discussMessage.replies_count != 0 && {discussMessage.replies_count} 回复 } { discussMessage.praise_num != 0 && {discussMessage.praise_num} 点赞 } @@ -378,7 +387,7 @@ class ShixunhomeWorkItem extends Component{ ` } - {this.props.isAdmin?

                  this.stopPro(event)} className={this.props.isAdminOrCreator()?"homepagePostSetting homepagePostSettingname":"homepagePostSetting homepagePostSettingbox"} style={{"right":"-2px","top":"44px","display":"block"}}> + {this.props.isAdmin?
                  this.stopPro(event)} className={this.props.isAdminOrCreator()?"homepagePostSetting homepagePostSettingname":"homepagePostSetting homepagePostSettingbox"} style={{"right":"-2px","top":"46px","display":"block"}}> 实训详情 {this.props.isAdminOrCreator()?this.editname(discussMessage.name,discussMessage.homework_id,event)} className={"btn colorblue ml20 font-16"}>重命名:""} {/* 设置*/} diff --git a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js index 8ffa8a1dd..0b5b04cfc 100644 --- a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js +++ b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunCustomsPass.js @@ -1,10 +1,10 @@ import React, {Component} from "react"; import {WordsBtn} from 'educoder'; -import {Table} from "antd"; +import {Table,InputNumber} from "antd"; import {Link,Switch,Route,Redirect} from 'react-router-dom'; import moment from 'moment'; import { MonacoDiffEditor } from 'react-monaco-editor'; - +import axios from 'axios'; class ShixunCustomsPass extends Component { constructor(props) { @@ -18,10 +18,51 @@ class ShixunCustomsPass extends Component { componentDidMount() { } + editgame_scores=(e,id,maxsum,code_rate,copy_user_id)=>{ + + let{datas}=this.state; + let newdatas=datas; + let score=e.target.value; + + if(score!=null&&score!=undefined&&score!=""){ + if(score<0){ + this.props.showNotification("不能小于0"); + this.setState({ + customsids:id + }) + }else if(score>maxsum){ + this.props.showNotification(`不能大于关卡分值${maxsum}`); + this.setState({ + customsids:id + }) + }else{ + let work_id=this.props.data.work_id; + let url=`/student_works/${work_id}/adjust_review_score.json` + axios.post(url,{ + type:"review", + score:score, + challenge_id:id, + code_rate:code_rate, + copy_user_id:copy_user_id + }).then((result)=>{ + if(result.data.status===0){ + this.props.updatas(); + this.props.showNotification(result.data.message); + }else{ + this.props.showNotification(result.data.message); + } + }).catch((error)=>{ + }) + } + }else{ + this.props.showNotification("调分为空将不会修改之前的分数"); + } + } render() { let {data}=this.props; - console.log(data) + let {customsids}=this.state; + // console.log(data) let datas=[]; data&&data.challenge_list.forEach((item,key)=>{ @@ -33,6 +74,8 @@ class ShixunCustomsPass extends Component { finishtime:item.copy_username, elapsedtime:item.copy_end_time===null?"无":item.copy_end_time===undefined?"无":item.copy_end_time===""?"无":moment(item.copy_end_time).format('YYYY-MM-DD HH:mm:ss'), empvalue:item.code_rate, + challenge_id:{id:item.id}, + copy_user_id:item.copy_user_id // adjustmentminute:asdasd }) }) @@ -112,6 +155,22 @@ class ShixunCustomsPass extends Component { render: (text, record) => ( {record.elapsedtime} + + ), + },{ + title: '调分', + key: 'adjustmentminute', + dataIndex: 'adjustmentminute', + + render: (text, record) => ( + + + {record.copy_user_id===null?"": this.editgame_scores(e,record.challenge_id.id,record.evaluating.all_score,record.empvalue,record.copy_user_id)} + // min={0} max={record.game_scores.game_score_full} + />} + + {/*查看*/} ), }, { @@ -138,7 +197,15 @@ class ShixunCustomsPass extends Component { // }, - + if(this.props.isAdmin()===false){ + columns.some((item,key)=> { + if (item.title === "调分") { + columns.splice(key, 1) + return true + } + } + ) + } return (
                  @@ -177,6 +244,9 @@ class ShixunCustomsPass extends Component { .customsPass{ text-align: left !important; } + .ant-table-thead > tr > th, .ant-table-tbody > tr > td { + padding: 16px 12px; + } `} {datas===undefined?"":
                  : -
                    @@ -286,7 +286,7 @@ class ShixunWorkModal extends Component{ group_list&&group_list.length===0?"":group_list.map((item,key)=>{ return(
                    -
                  • +
                  • + className="task-hide color-grey-name" title={item===undefined?"":item.name}>{item===undefined?"":item.name}
                  • diff --git a/public/react/src/modules/courses/shixunHomework/ShowAppraiseList.js b/public/react/src/modules/courses/shixunHomework/ShowAppraiseList.js new file mode 100644 index 000000000..f52491ed0 --- /dev/null +++ b/public/react/src/modules/courses/shixunHomework/ShowAppraiseList.js @@ -0,0 +1,176 @@ +import React,{ Component } from "react"; +import { Modal,Checkbox,Upload,Button,Icon,message,Input,Radio} from "antd"; +import { WordNumberTextarea,markdownToHTML } from 'educoder'; +import axios from 'axios'; +import './style.css'; + +class ShowAppraiseList extends Component{ + constructor(props){ + super(props); + this.state={ + + } + } + + + + render(){ + let {data, work_comment,work_comment_hidden}=this.props; + let work_commenttype=work_comment===undefined||work_comment===null||work_comment===""; + let work_comment_hiddentype=work_comment_hidden===undefined||work_comment_hidden===null||work_comment_hidden===""; + + return( +
                    + + {data===undefined?"":work_commenttype===true&&work_comment_hiddentype===true?"": +
                    +
                    + +
                    + 总体评阅评阅内容 + + {this.props&&this.props.isAdmin()===true?this.props.isdeleteModal(data.comment_id,true,"main")} + >删除:""} + + {this.props&&this.props.isAdmin()===true?this.props.showAppraiseModal("main",undefined,work_comment,work_comment_hidden)} + >编辑:""} + +
                    + + {this.props&&this.props.isAdmin()===true? +
                    + + {work_commenttype===true?"":
                    + 学生可见(学生可查看老师的评阅内容) +
                    } + + {work_commenttype===true?"":
                    +
                    +
                    +
                    +
                    } + + {work_comment_hiddentype===true?"":
                    + 学生不可见(仅对课堂老师可见) +
                    } + + {work_comment_hiddentype===true?"":
                    +
                    +
                    +
                    +
                    } + + +
                    :
                    +
                    +
                    +
                    +
                    +
                    +
                    } + +
                    +
                    } + + + + + + {data===undefined?"":data.stage_list===undefined||data.stage_list===null?"":data.stage_list.map((item,key)=>{ + let challenge_comment_hidden=item.challenge_comment_hidden===undefined||item.challenge_comment_hidden===null||item.challenge_comment_hidden===""; + let challenge_comment=item.challenge_comment===undefined||item.challenge_comment===null||item.challenge_comment===""; + + return( +
                    + {challenge_comment===false||challenge_comment_hidden==false?
                    +
                    + +
                    + 第{key+1}关{item.name} + {this.props&&this.props.isAdmin()===true?this.props.isdeleteModal(item.comment_id,true,"child")} + >删除:""} + + {this.props&&this.props.isAdmin()===true?this.props.showAppraiseModal("child",item.challenge_id,item.challenge_comment,item.challenge_comment_hidden)} + >编辑:""} +
                    + + {this.props&&this.props.isAdmin()===true? +
                    + + {challenge_comment===true?"":
                    + 学生可见(学生可查看老师的评阅内容) +
                    } + + {challenge_comment===true?"":
                    +
                    +
                    +
                    +
                    } + + {challenge_comment_hidden===true?"":
                    + 学生不可见(仅对课堂老师可见) +
                    } + {challenge_comment_hidden===true?"":
                    +
                    +
                    +
                    +
                    } + +
                    :
                    +
                    +
                    +
                    +
                    +
                    +
                    } + +
                    +
                    :""} + +
                    ) + }) + } + + +
                    + ) + } +} +export default ShowAppraiseList; + diff --git a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js index bd90db42f..90fb3939b 100644 --- a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js +++ b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js @@ -86,13 +86,13 @@ class Trainingjobsetting extends Component { latepenaltytype: false, unifiedsetting: true, allowreplenishment: undefined, - completionefficiencyscore: true, + completionefficiencyscore: false, whethertopay: false, proportion: undefined, level: undefined, ealuation: false, latededuction: undefined, - latedeductiontwo: "20", + latedeductiontwo: "0", database: false, datasheet: false, databasetwo: undefined, @@ -120,8 +120,10 @@ class Trainingjobsetting extends Component { showmodel:false, code_review:false, testscripttiptype:false, + end_timebool:false, late_timesbool:false, + work_efficiencys:false, } // console.log("获取到的值") // console.log("Trainingjobsetting") @@ -283,7 +285,7 @@ class Trainingjobsetting extends Component { allowreplenishment: result.data.allow_late, latededuction: result.data.late_penalty, level: result.data.answer_open_evaluation === true ? "满分" : "扣分", - completionefficiencyscore: result.data.work_efficiency, + work_efficiencys: result.data.work_efficiency, latedeductiontwo: result.data.eff_score, proportion: result.data.shixun_evaluation === 0 ? "均分比例" : result.data.shixun_evaluation === 1 ? "经验值比例" : result.data.shixun_evaluation === 2 ? "自定义分值" : "", publicwork: result.data.work_public, @@ -634,7 +636,7 @@ class Trainingjobsetting extends Component { late_penalty: parseInt(this.state.latededuction), //迟交扣分 late_time: moment(this.state.late_time).format('YYYY-MM-DD HH:mm'), //结束时间 answer_open_evaluation: this.state.level === "满分" ? true : false, //扣分项 - work_efficiency: this.state.completionefficiencyscore, //完成效率评分占比 + work_efficiency: this.state.work_efficiencys, //完成效率评分占比 eff_score: this.state.completionefficiencyscore === true ? this.state.latedeductiontwo : undefined,//占比分 shixun_evaluation: this.state.proportion === "均分比例" ? 0 : this.state.proportion === "经验值比例" ? 1 : this.state.proportion === "自定义分值" ? 2 : 0, challenge_settings: array, @@ -659,6 +661,7 @@ class Trainingjobsetting extends Component { flagPageEditsthrees:false, flagPageEditsfor:false, whethertopay:false, + completionefficiencyscore:false, }) this.refs.targetElementTrainingjobsetting.scrollIntoView() @@ -862,19 +865,19 @@ class Trainingjobsetting extends Component { var exams = parseFloat(Proportion.toFixed(1)); var intk = srorelength*exams; intkk=oushution - intk; - console.log("奇数"); - console.log(srorelength);//3 - console.log(oushution);//79 - console.log(exams);//26.3 - console.log(intk);//78.9 - console.log(intkk); + // console.log("奇数"); + // console.log(srorelength);//3 + // console.log(oushution);//79 + // console.log(exams);//26.3 + // console.log(intk);//78.9 + // console.log(intkk); }else { // 偶数 var examsy =parseFloat(Proportion.toFixed(1)); intkks=oushution - (examsy*srorelength); - console.log("偶数"); - console.log(oushution); - console.log((examsy*srorelength)); + // console.log("偶数"); + // console.log(oushution); + // console.log((examsy*srorelength)); } var mact=0; @@ -1003,6 +1006,7 @@ class Trainingjobsetting extends Component { this.state.latedeductiontwo=20; this.setState({ completionefficiencyscore: e.target.checked, + work_efficiencys:e.target.checked, latedeductiontwo: 20, }) //均分比例 @@ -1019,6 +1023,7 @@ class Trainingjobsetting extends Component { this.state.latedeductiontwo=0; this.setState({ completionefficiencyscore: e.target.checked, + work_efficiencys:e.target.checked, latedeductiontwo: 0, }) //均分比例 @@ -1067,7 +1072,7 @@ class Trainingjobsetting extends Component { // //占比分 changeTopicNametwo = (value) => { - // console.log("2e.target.value", value) + // console.log("TrainingjobsettingTrainingjobsetting", value) if (value === "" || value === undefined) { return } @@ -1694,15 +1699,78 @@ class Trainingjobsetting extends Component { if(this.state.allowreplenishment === false){ whethertopays=false; } - this.setState({ - flagPageEditsbox:true, - flagPageEdit: true, - whethertopay:whethertopays, - flagPageEditstwo:releasetime, - flagPageEditsthrees:deadline, - flagPageEditsfor:endtime, - unifiedsetting:this.state.unifiedsetting, - }) + if(this.state.jobsettingsdata!==undefined){ + + } + + try { + if(this.state.jobsettingsdata&& this.state.jobsettingsdata.data.homework_status[0]==="未发布"){ + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + completionefficiencyscore:true, + work_efficiencys:true, + unifiedsetting:this.state.unifiedsetting, + latedeductiontwo:20, + }); + //均分比例 + try { + if(this.state.proportion==="均分比例"){ + this.Equalproportion(20); + + }else if(this.state.proportion==="经验值比例"){ + this.Empiricalvalueratio(20); + + } + }catch (e) { + + } + + }else { + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + unifiedsetting:this.state.unifiedsetting, + }); + if(this.state.work_efficiencys===true){ + this.setState({ + completionefficiencyscore:true, + }) + }else{ + this.setState({ + completionefficiencyscore:false, + }) + } + } + }catch (e) { + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + unifiedsetting:this.state.unifiedsetting, + }); + if(this.state.work_efficiencys===true){ + this.setState({ + completionefficiencyscore:true, + }) + }else{ + this.setState({ + completionefficiencyscore:false, + }) + } + } + if(this.state.proportion === "自定义分值"){ this.setState({ boolUnitetwoname:"自定义分值", @@ -1715,7 +1783,121 @@ class Trainingjobsetting extends Component { } catch (e) { } + }; + //一进来就是老师要用的编辑页面 + editSettings=(datas)=>{ + console.log("编辑页面"); + console.log(datas); + try { + if (datas.data.is_end === true) { + this.setState({ + modalsType: true, + modalsTopval: "课堂已结束不能再修改!", + loadtype: true, + modalSave: this.cancelBox + }) + } else { + var releasetime =true; + var deadline = true; + var endtime =true; + var whethertopays =true; + //发布时间 + + if(moment(datas.data.publish_time,"YYYY-MM-DD HH:mm")<=moment()){ + releasetime=false; + } + //截止时间 + if(moment(datas.data.end_time,"YYYY-MM-DD HH:mm")<=moment()){ + deadline=false; + } + //结束时间 + if(moment(datas.data.late_time,"YYYY-MM-DD HH:mm")<=moment()){ + endtime=false; + } + if(datas.data.allowreplenishment === false){ + whethertopays=false; + } + + try { + if(datas.data&& datas.data.homework_status[0]==="未发布"){ + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + completionefficiencyscore:true, + work_efficiencys:true, + unifiedsetting:datas.data.unifiedsetting, + latedeductiontwo:20, + }); + //均分比例 + try { + if(datas.data.proportion==="均分比例"){ + this.Equalproportion(20); + + }else if(datas.data.proportion==="经验值比例"){ + this.Empiricalvalueratio(20); + + } + }catch (e) { + + } + + }else { + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + unifiedsetting:datas.data.unifiedsetting, + }); + if(datas.data.work_efficiencys===true){ + this.setState({ + completionefficiencyscore:true, + }) + }else{ + this.setState({ + completionefficiencyscore:false, + }) + } + } + }catch (e) { + this.setState({ + flagPageEditsbox:true, + flagPageEdit: true, + whethertopay:whethertopays, + flagPageEditstwo:releasetime, + flagPageEditsthrees:deadline, + flagPageEditsfor:endtime, + unifiedsetting:datas.data.unifiedsetting, + }); + if(datas.data.work_efficiencys===true){ + this.setState({ + completionefficiencyscore:true, + }) + }else{ + this.setState({ + completionefficiencyscore:false, + }) + } + } + + if(datas.data.proportion === "自定义分值"){ + this.setState({ + boolUnitetwoname:"自定义分值", + boolUnitetwo: false, + flagPageEdits:true, + }) + } + + } + } catch (e) { + } } //取消编辑 cancelEdit = () => { @@ -1733,6 +1915,8 @@ class Trainingjobsetting extends Component { hand__e_tip: "", hand_flags: false, handclass: undefined, + completionefficiencyscore:false, + latedeductiontwo:0, unit_e_tip: "", }) this.refs.targetElementTrainingjobsetting.scrollIntoView(); @@ -1847,9 +2031,9 @@ class Trainingjobsetting extends Component { const dataformat = 'YYYY-MM-DD HH:mm'; - let {flagPageEdit,testscripttiptype,publish_timebool,end_timebool,late_timesbool,flagPageEdits,flagPageEditstwo,flagPageEditsbox,whethertopay,handclass,flagPageEditsthrees, flagPageEditsfor,rules,rulest,unifiedsetting,group_settings, course_group,unit_e_tip, borreds,borredss,unit_p_tip, end_time, late_time, score_open, publish_time, starttimetype, modalsType, modalsTopval, loadtype, modalSave, endtimetype, latetimetype, allowlate, latepenaltytype, jobsettingsdata, endOpen, mystyle, mystyles} = this.state; - console.log(publish_timebool); - console.log(!flagPageEditstwo); + let {flagPageEdit,testscripttiptype,publish_timebool,end_timebool,late_timesbool,work_efficiencys,flagPageEdits,flagPageEditstwo,flagPageEditsbox,whethertopay,handclass,flagPageEditsthrees, flagPageEditsfor,rules,rulest,unifiedsetting,group_settings, course_group,unit_e_tip, borreds,borredss,unit_p_tip, end_time, late_time, score_open, publish_time, starttimetype, modalsType, modalsTopval, loadtype, modalSave, endtimetype, latetimetype, allowlate, latepenaltytype, jobsettingsdata, endOpen, mystyle, mystyles} = this.state; + // console.log(publish_timebool); + // console.log(!flagPageEditstwo); const radioStyle = { display: 'block', height: '30px', @@ -1875,6 +2059,8 @@ class Trainingjobsetting extends Component { // } // console.log(this.props.isAdmin()) // console.log(this.state.code_review===false) + // console.log("引入的分值"); + // console.log(this.state.work_efficiencys); return (
                    {this.state.showmodel===true? 效率分效率分(选中,则学生最终成绩包含效率分)
                    @@ -2139,7 +2325,7 @@ class Trainingjobsetting extends Component {
                    分值 - diff --git a/public/react/src/modules/courses/shixunHomework/shixunHomework.js b/public/react/src/modules/courses/shixunHomework/shixunHomework.js index dd694828a..eb59ce6f1 100644 --- a/public/react/src/modules/courses/shixunHomework/shixunHomework.js +++ b/public/react/src/modules/courses/shixunHomework/shixunHomework.js @@ -1,11 +1,12 @@ import React,{ Component } from "react"; import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin } from "antd"; import { WordsBtn,on, off, trigger } from 'educoder'; -import CourseLayoutcomponent from '../common/CourseLayoutComponent'; +import {BrowserRouter as Router,Route,Switch,Link} from 'react-router-dom'; import axios from'axios'; import HomeworkModal from "../coursesPublic/HomeworkModal"; import ShixunModal from "../coursesPublic/ShixunModal"; import PathModal from "../coursesPublic/PathModal"; +import NewShixunModel from '../coursesPublic/NewShixunModel'; import AddcoursesNav from "../coursesPublic/AddcoursesNav"; import Modals from '../../modals/Modals'; import moment from 'moment'; @@ -112,7 +113,7 @@ class ShixunHomework extends Component{ let coursesId=this.props.match.params.coursesId; let url="/courses/"+coursesId+"/homework_commons.json?type=4"; - axios.get(url,{ + axios.get(encodeURI(url),{ params: { search:undefined, page:1, @@ -445,18 +446,18 @@ class ShixunHomework extends Component{ } - // 选用实训 - createCommonWork=()=>{ - - this.setState({ - hometypepvisible:true, - shixunmodal:true, - patheditarry:[], - checkBoxValues:[] - }) - - - } + // // 选用实训 + // createCommonWork=()=>{ + // + // this.setState({ + // hometypepvisible:true, + // shixunmodal:true, + // patheditarry:[], + // checkBoxValues:[] + // }) + // + // + // } // 选用实训路径 createCommonpath=()=>{ @@ -502,9 +503,9 @@ class ShixunHomework extends Component{ // }).then((result)=>{ // if(result.status===200){ // - // let shixun_list=result.data.shixun_list; - // for(var i=0; i{ // if(result.status===200){ // - // let shixun_list=result.data.subject_list; - // for(var i=0; i{ + this.setState({ + NewShixunModelType:true, + patheditarry:[], + checkBoxValues:[] + }) + } + hideNewShixunModelType=()=>{ + this.setState({ + NewShixunModelType:false + }) + } render(){ let { modalname, @@ -931,14 +944,32 @@ class ShixunHomework extends Component{ course_modules, shixunpath, order, - antIcon, + NewShixunModelType, }=this.state; let main_id=this.props.match.params.main_id; let category_id=this.props.match.params.category_id; + return(
                    + + {/*新版实训model*/} + {NewShixunModelType===true?this.hideNewShixunModelType()} + coursesId={this.props.match.params.coursesId} + homeworkupdatalists={(Coursename,page,order)=>this.homeworkupdatalist(Coursename,page,order)} + Coursename={Coursename} + page={page} + order={order} + statustype={'published'} + />:""} + + {/*提示*/} {Modalstype&&Modalstype===true?this.getcourse_groupslist(id)} />:""} - {/*选择实训*/} - {shixunmodal===true?this.homeworkupdatalist(Coursename,page,order)} - hometypepvisible={hometypepvisible} - hidecouseShixunModal={this.hidecouseShixunModal} - newshixunmodallist={newshixunmodallist} - coursesId={this.props.match.params.coursesId} - courseshomeworkstart={(category_id,homework_ids)=>this.newhomeworkstart(category_id,homework_ids)} - funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)} - patheditarry={patheditarry} - />:""} + {/*/!*选择实训*!/*/} + {/*{shixunmodal===true?this.homeworkupdatalist(Coursename,page,order)}*/} + {/*hometypepvisible={hometypepvisible}*/} + {/*hidecouseShixunModal={this.hidecouseShixunModal}*/} + {/*newshixunmodallist={newshixunmodallist}*/} + {/*coursesId={this.props.match.params.coursesId}*/} + {/*courseshomeworkstart={(category_id,homework_ids)=>this.newhomeworkstart(category_id,homework_ids)}*/} + {/*funpatheditarry={(patheditarry)=>this.funpatheditarry(patheditarry)}*/} + {/*patheditarry={patheditarry}*/} + {/*/>:""}*/} {shixunmodal===true||shixunpath===true?
                  { - datas.push({ - customs: key+1, - taskname:{name:item.name,complete_status:item.complete_status}, - openingtime:item.open_time, - evaluating: item.evaluate_count, - finishtime:item.finished_time, - elapsedtime:item.time_consuming, - empvalue:{myself:item.myself_experience,experience:item.experience}, - game_scores:{game_score:item.game_score,game_score_full:item.game_score_full}, - challenge_id:{id:item.challenge_id} - // adjustmentminute:asdasd - }) - }) - this.setState({ - datas:datas - }) - } } myjumptopic=(e)=>{ console.log("获取到值"); @@ -96,7 +74,28 @@ class OfficialAcademicTranscript extends Component { } render() { - let {datas,customsids}=this.state; + let {customsids}=this.state; + let {data}=this.props; + + let datas=[]; + if(data!=undefined){ + data.stage_list===undefined?"":data.stage_list.forEach((item,key)=>{ + datas.push({ + customs: key+1, + taskname:{name:item.name,complete_status:item.complete_status}, + openingtime:item.open_time, + evaluating: item.evaluate_count, + finishtime:item.finished_time, + elapsedtime:item.time_consuming, + empvalue:{myself:item.myself_experience,experience:item.experience}, + game_scores:{game_score:item.game_score,game_score_full:item.game_score_full}, + challenge_id:{id:item.challenge_id}, + challenge_comment: item.challenge_comment, + challenge_comment_hidden: item.challenge_comment_hidden, + // adjustmentminute:asdasd + }) + }) + } let columns=[{ title: '关卡', @@ -150,7 +149,7 @@ class OfficialAcademicTranscript extends Component { ), }, { - title: '耗时', + title: '实战耗时', key: 'elapsedtime', dataIndex: 'elapsedtime', @@ -196,6 +195,20 @@ class OfficialAcademicTranscript extends Component { // min={0} max={record.game_scores.game_score_full} /> {/*查看*/} + + ), + },{ + title: '操作', + key: 'operation', + dataIndex: 'operation', + + render: (text, record) => ( + + + this.props.showAppraiseModal("child",record.challenge_id.id,record.challenge_comment,record.challenge_comment_hidden)} + >评阅 ), }]; @@ -210,6 +223,13 @@ class OfficialAcademicTranscript extends Component { } } ) + columns.some((item,key)=> { + if (item.title === "操作") { + columns.splice(key, 1) + return true + } + } + ) } return (
                  @@ -276,6 +296,9 @@ class OfficialAcademicTranscript extends Component { .linhe15{ line-height: 15px; } + .mr22{ + margin-right: 22px; + } `} {datas===undefined?"":
                • {data&&data.username}
                • -
                • {data!==undefined?"--":data.student_id===undefined?"--":data.student_id===null?"--":data.student_id}
                • +
                • {data===undefined?"--":data.student_id===undefined?"--":data.student_id===null?"--":data.student_id}
                • {data&&data.echart_data===undefined?"":data&&data.echart_data.myself_eff[1]}
                • {data&&data.echart_data===undefined?"":data&&data.echart_data.myself_eff[0]}
                • @@ -396,7 +400,7 @@ class Shixunechart extends Component {
                • {data&&data.username}
                • -
                • {data!==undefined?"--":data.student_id===undefined?"--":data.student_id===null?"--":data.student_id}
                • +
                • {data===undefined?"--":data.student_id===undefined?"--":data.student_id===null?"--":data.student_id}
                • {data&&data.echart_data===undefined?"":data&&data.echart_data.myself_object[1]}
                • diff --git a/public/react/src/modules/courses/shixunHomework/style.css b/public/react/src/modules/courses/shixunHomework/style.css index f2b0c39ed..1af39e7ce 100644 --- a/public/react/src/modules/courses/shixunHomework/style.css +++ b/public/react/src/modules/courses/shixunHomework/style.css @@ -45,7 +45,28 @@ cursor: default; } .maxnamewidth110{ - max-width: 110px; + 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; +} +.maxnamewidth145{ + max-width: 145px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; @@ -53,4 +74,17 @@ } .ysyslxh{ background: #fafafa; +} + +.z666{ + color: #666; + font-size:14px; +} +.z000{ + color: #000; + font-size:16px; +} + +.pd30bt{ + padding: 10px 30px 0px 30px; } \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css b/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css new file mode 100644 index 000000000..87f87fc8e --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css @@ -0,0 +1,364 @@ +.eaSystemp a{ + color:#05101a; +} +.eaSystemp span{ + color: #05101a !important; +} +.eacourse p{ + height:84px; + margin-bottom:0px !important; +} +.eacourse #training_objective_contents{ + height:81px; +} +.courseSystem{ +font-size:18px; +font-family:MicrosoftYaHei; +font-weight:400; +line-height:45px; +color:rgba(5,16,26,1); +} +.SystemParameters{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + line-height:45px; + color:rgba(50,50,50,1); +} +.Systemnum{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + color:#FF6800; +} +.newSystem{ + width:1200px; + overflow:auto; + background: #FFF; +} +.newSystem .clearfix .column-1{ + width: 113px !important; + text-align: center; +} +.operationColumn{ + margin: 0px 10%; + width:100%; + height:100%; +} +.operationalter{ + margin: 20px 16px; +} +.SystemModifythelist .column-1{ + width: 120px !important; + text-align: center; +} + +.SystemModifythelist .column-3{ + padding-left: 96px; + margin-right: 23px; +} +.operationright{ + float:right !important; +} + +.newSystem p{ + /*padding: 10px 33px !important;*/ + margin-bottom: 0em; +} +.newSystem li{ + margin:0 !important; +} +.SystemModifythelist{ + background:#FFF !important; +} + +.SystemModifythelist .column-1:nth-child(1){ + margin-left: 7px; +} + +.Systempoint{ + font-size:12px; + font-family:MicrosoftYaHei; + font-weight:400; + color:rgba(152,152,152,1); +} +.editorModify{ + background:#FFF !important; +} +.newSystem .editorModify .column-1{ + width: 194px !important; + text-align: left; + margin-left: 30px; +} +.newSystem .editorModify .column-1:nth-child(1){ + margin-right: 510px; +} +.editorModify .ant-select{ + width: 556px !important; + margin-left: 36px; +} +.editorModify .ant-select .ant-select-selection{ + height: 30px !important; +} +.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered{ + height: 30px !important; +} +.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered .ant-select-selection-selected-value{ + line-height: 30px !important; +} +.inputWeight{ + width: 20%; + font-size:14px; + height:30px; + margin-left: 20px; + background-color: #F5F5F5; +} +.SetTheAssociated{ + width: 314px; + height: 30px; + float: right; + margin-right: -3.5%; +} +.SetTheAssociatedchild{ + width: 120px; + height: 30px; + background: rgba(255,255,255,1); + border: 1px solid rgba(234,234,234,1); + border-radius: 4px; + float: left; + margin-right: 10px; + text-align: center; + line-height: 30px; + /*margin-left: 34px;*/ +} +.operatebutton{ + margin-left: 20px; + /* margin-top: 16px; */ +} +.editbulebutton{ + width:120px; + height:30px; + background:rgba(76,172,255,1); + border-radius:2px; + color:#FFF; + text-align: center; + line-height: 30px; +} +.editglybutton{ + width:120px; + height:30px; + border:1px solid rgba(205,205,205,1); + border-radius:2px; + color:#999; + text-align: center; + line-height: 30px; +} + +.editglybuttonbox{ + width: 275px; + margin-bottom: 30px; + margin-right: 20px; + margin-right:7%; +} +.editglybuttonboxs{ + width: 275px; + margin-bottom: 30px; + margin-right: 20px; + margin-right:3%; +} +.defalutCancelbtn:hover { + border: 1px solid #B2B2B2; + color: #B2B2B2!important; +} + +.gouxuanbule{ + color:#4CACFF; +} +.gouxuanwhite{ + color:#FFF; +} +.icon-gouxuan{ + cursor: pointer; +} +/* 谷歌 */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; +} +/* 火狐 */ +input{ + -moz-appearance:textfield; +} +.inputWeight{ + text-indent:0.625rem; +} + +.columnlocation{ + height: 40px; + line-height: 40px; +} +.paddingLF{ + padding:0 33px; +} +.width20{ + width: 20px; + height: 20px; + text-align: center; +} +.defalutSubmitbtn,.defalutCancelbtn{ + cursor: pointer; +} +.mb290{ + margin-bottom:290px; +} +.Spinlarge{ + text-align: center; + width: 100%; + margin-top: 25px; + margin-bottom: 25px; +} +.DDred{ + color:#DD1717; +} +.color-666{ + color:#666666 !important; +} +.color-05101A{ + color:#05101A !important; +} +.ec_graduation_name{ + margin-right:20px !important; +} +.column-width575{ + color: transparent !important; +} +.column-width130{ + width: 130px !important; + height: 40px; +} + + +.ListTableLine li>span { + max-width: 550px !important; +} + +.graduateRequirement .clearfix .column-1 { + width: 76px!important; +} + +.newrightcalculatebutton{ + width: 50px; + height: 25px; + border: 1px solid rgba(76,172,255,1); + border-radius: 1px; + line-height: 25px; + text-align: center; + margin-top: 7px; + cursor: pointer; + color: rgba(76,172,255,1); +} +.columnbox{ + height: 53px; + overflow: hidden; +} + +.ant-modal-mask { + background-color: rgba(5,16,26,0.4); +} +.ecmodeldelet{ + top:300px; +} +.ecmodeldelet .ant-modal-header{ + padding: 0px 24px; +} +.ecmodeldelet .ant-modal-title{ + padding: 0px 15px; + text-align: center; + box-sizing: border-box; + line-height: 70px; + height: 70px; + border-radius: 10px 10px 0px 0px; + font-size: 16px; + font-weight: bold; +} +.bor-red { + border: 1px solid #db0505 !important; +} + +.ml93{ + margin-left:93px; +} +.ml26{ + margin-left: 26px; +} +.finishtarget{ + width: 69px; + /* height: 48px; */ + line-height: 20px; + text-align: center; + margin-right: 48px; +} + +.bordereaeaea{ + border-bottom: 1px solid transparent !important; +} + +.heightimportant{ + height: 30px !important; + background-color: #F5F5F5; +} +.heightimportant:focus { + background-color: #fff; +} +.inputWeight:focus { + background-color: #fff; + } +.heightlineimportant{ + line-height: 30px !important; +} + +.ant-select-selection:hover{ + border-color: #d9d9d9 !important; +} +.ant-input:focus { + outline: 0; + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + .ant-input{ + border-color: #d9d9d9 !important; + } + .ant-select-selection:focus{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + .ant-select-selection:active{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + + .ant-select-selection:focus{ + border-color: #d9d9d9 !important; + } + .ant-select-selection{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + +.mt60{ + margin-top:60px; +} + + +.editlybuttonbox{ + margin-bottom: 30px; + margin-right: 3%; +} + +.Importclassroomdata{ + top: 30px; + position: absolute; + right: 0px; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js new file mode 100644 index 000000000..511a0da64 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js @@ -0,0 +1,802 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import axios from 'axios'; + +import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd'; + +import './ecCourseSupports.css'; + +const $ = window.$; +class CourseSupports extends Component { + constructor(props) { + super(props) + this.state={ + data:'', + ec_courses_list:[], + editcourse:[{"weights": 0, + "ec_course_name":'', + "top_relation": false, + "ec_course_id":'' + }], + editnum:0, + index:0, + ec_graduation_subitem_id:0, + ec_year_id:0, + schooldata:{}, + spinning:true, + ecComponentState:'ecCourseSupports', + supportid:null, + Editkey:null, + titlemessage:"提示", + Supportstype:false, + Supportslist:'', + Supportssum:false, + Supportsclass:false, + Supportsclasskey:undefined, + neweditcourse:[{"weights": 0, + "ec_course_name":'', + "top_relation": false, + "ec_course_id":'' + }], + max_support_count:0 + } + } + + componentWillMount(){ + this.setState({ + ec_year_id:this.props.match.params.ec_year_id, + major_school_id:this.props.match.params.major_school_id + }) + window.document.title = '课程体系 vs 毕业要求'; + } + + UpdateClassData=()=>{ + + let ec_year_id=this.props.match.params.ec_year_id; + + this.setState({ + ec_year_id:ec_year_id + }) + + const url = `/ec_years/${ec_year_id}/graduation_course_supports.json`; + axios.get(url) + .then((response) => { + if(response.status===200){ + if(response.data.graduation_subitems.length===0){ + this.setState({ + Supportstype:true, + data:response.data, + Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据' + }) + }else{ + let datas=response.data.graduation_subitems; + let listlength=[] + datas.map((item,key)=>{ + listlength.push(item.course_supports.length) + }) + + let max_support_count=Math.max(...listlength); + + this.setState({ + max_support_count:max_support_count, + data:response.data + }) + } + } + + }) + .catch(function (error) { + console.log(error); + }); + + const zrl = `/ec_years/${ec_year_id}/ec_courses/search.json`; + axios.get(zrl,{params:{ + per_page:10000, + } + }) + .then((response) => { + + if(response.status===200){ + this.setState({ + ec_courses_list:response.data.ec_courses + }) + } + + }) + .catch(function (error) { + console.log(error); + }); + + } + componentDidMount(){ + this.setState({ + ec_year_id:this.props.match.params.ec_year_id, + major_school_id:this.props.match.params.major_school_id + }) + this.UpdateClassData(); + + } + EditSupportCourse=(keys,e)=>{ + $('#school_major_list').scrollLeft(0); + let id=e.target.id; + id=parseInt(id); + + let subindex =e.target.getAttribute("subindex"); + + // const url = `/ec_course_supports/edit_require_vs_course?subitem_id=`+id + // axios.get(url) + // .then((response) => { + // + // if(response.status===200){ + + // + // this.setState({ + // ec_courses_list:response.data.ec_courses_list, + // editcourse:support_data, + // index:subindex, + // ec_graduation_subitem_id:id, + // Supportssum:false, + // Supportsclass:false, + // }) + // + // let {editcourse} =this.state; + // let neweditcourse=editcourse; + // let newnum=0; + // for(var j=0;j{ + if(keys===key){ + + if(item.course_supports.length>0){ + this.setState({ + editcourse:item.course_supports, + neweditcourse:item.course_supports, + Editkey:key, + index:subindex, + ec_graduation_subitem_id:id, + }) + }else if(item.course_supports.length===0){ + this.setState({ + editcourse:[{weights: 0,top_relation: false,ec_course_name:'',ec_course_id:''}], + neweditcourse:[{weights: 0,top_relation: false,ec_course_name:'',ec_course_id:''}], + Editkey:key, + index:subindex, + ec_graduation_subitem_id:id, + }) + } + + } + }) + + let newnum=0; + + data.graduation_subitems.map((item,key)=>{ + if(keys===key){ + item.course_supports.map((items,keys)=>{ + if(items.weights===undefined){ + newnum=0 + }else{ + newnum=newnum+items.weights; + } + }) + } + }) + + newnum= Math.round(newnum*100)/100; + + this.setState({ + editnum:newnum + }) + console.log(newnum) + + // $("#school_ListTableLine").show(); + // let offsettop=$("#school_ListTableLine").position().top||$("#school_ListTableLine").scrollTop || $("#school_ListTableLine").pageYOffset; + // window.scrollTo(0, offsettop) + } + + Addcourse=(e)=>{ + let {editcourse} =this.state; + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + + let neweditcourse=arr; + let newadd = {weights: 0,top_relation: false,ec_course_name:'',ec_course_id:''}; + neweditcourse.push(newadd); + this.setState({ + editcourse:neweditcourse + }) + } + editcourse=(neweditcourse)=>{ + this.setState({ + editcourse:neweditcourse + }) + + } + + Deletcourse=(e)=>{ + // 删除 + // let id =e.target.getAttribute("index"); + let {editcourse} = this.state; + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + + let neweditcourse=arr; + if(neweditcourse.length>1){ + neweditcourse.splice(e,1); + let newnum=0; + for(var j=0;j{ + let {editcourse} = this.state; + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + + let neweditcourse=arr; + var id=e.target.id; + var value=parseFloat(e.target.value); + if(isNaN(value)){ + value="" + } + var x = String(value).indexOf('.') + 1; + var y = String(value).length - x; + if(y > 2){ + this.setState({ + // Supportstype:true, + Supportslist:'请精确到2位数', + Supportssum:true + }) + return + }else{ + this.setState({ + Supportssum:false + }) + } + + + const person = new Object (); + person.weights=value; + person.ec_course_id= neweditcourse[id].ec_course_id; + person.ec_course_name=neweditcourse[id].ec_course_name; + person.top_relation=neweditcourse[id].top_relation; + + + neweditcourse[id]=person; + + let newnum=0; + for(var j=0;j1){ + this.setState({ + // Supportstype:true, + Supportslist:'权重之和不能大于1', + Supportssum:true + }) + }else{ + this.setState({ + Supportssum:false + }) + } + + } + handleChange=(e)=> { + + let {editcourse} = this.state; + + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + let neweditcourse=arr; + + let value=`${e[0]}`; + value=parseInt(value) + let num=`${e[1]}`; + num=parseInt(num) + + for(var z=0;z{ + + let {editcourse} = this.state; + + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + + let neweditcourse=arr; + let id =e.target.getAttribute("itindex"); + for(var i=0;i<1;i++){ + neweditcourse[id].top_relation=false; + } + + this.editcourse(neweditcourse); + } + + relevancebottom=(e)=>{ + + let {editcourse} = this.state; + let arr=new Array(); + editcourse.map((item,key)=>{ + arr.push(item) + }) + let neweditcourse=arr; + let id =e.target.getAttribute("itindex"); + for(var i=0;i<1;i++){ + neweditcourse[id].top_relation=true; + } + + this.editcourse(neweditcourse); + } + focus() { + this.inputNumberRef.focus(); + } + + blur() { + this.inputNumberRef.blur(); + } + CancelSupports=()=>{ + let{editcourse,neweditcourse}=this.state; + // + // console.log(editcourse) + // console.log(neweditcourse) + + this.setState({ + Editkey:null, + Supportssum:false, + Supportsclass:false, + editcourse:neweditcourse + }) + } + SubmitClassData=()=>{ + let {editcourse,editnum,ec_graduation_subitem_id} = this.state; + if(editcourse.length===0){ + this.setState({ + // Supportstype:true, + Supportslist:'保存失败,至少保留一个课程', + Supportssum:true + }) + return + } + if(editnum>1||editnum===0){ + this.setState({ + // Supportstype:true, + Supportslist:'保存失败,权重大于1或为空', + Supportssum:true + }) + return + } + + // for(var p=0; p{ + if(item.weights===""){ + item.weights=0; + } + if(item.ec_course_id===""){ + this.setState({ + // Supportstype:true, + Supportslist:'保存失败,课程不能为空', + Supportsclass:true, + Supportsclasskey:key + }) + return + } + }) + + + + + var Url = `/ec_years/${this.props.match.params.ec_year_id}/graduation_course_supports.json`; + axios.post(Url, { + graduation_subitem_id :ec_graduation_subitem_id, + course_supports: editcourse + } + ).then((response) => { + if(response.data.id===ec_graduation_subitem_id){ + + // this.setState({ + // Editkey:null, + // Supportslist:"保存成功", + // Supportstype:true, + // Supportssum:false, + // Supportsclass:false, + // Supportsclasskey:undefined, + // }) + this.UpdateClassData(); + this.setState({ + Editkey:null, + Supportssum:false, + Supportsclass:false, + }) + }else if(response.data.status===-1){ + // this.setState({ + // Supportslist:"参数错误", + // Supportstype:true, + // Supportssum:false, + // Supportsclass:false, + // Supportsclasskey:undefined, + // }) + } + }).catch((error) => { + console.log(error) + }) + } + Deletcourses=(key)=>{ + this.setState({ + supportid:key, + Supportslist:"您确定要删除吗?", + Supportstype:true + }) + } + hideSupports=()=>{ + this.setState({ + Supportstype:false, + supportid:null, + Supportslist:"", + }) + } + + confirmysl(url){ + axios.get(url + '?export=true').then((response) => { + if(response.data.status&&response.data.status===-1){ + + }else if(response.data.status&&response.data.status===-2){ + if(response.data.message === "100"){ + // 已超出文件导出的上限数量(100 ),建议: + + this.setState({ + DownloadType:true, + DownloadMessageval:100 + }) + }else { + //因附件资料超过500M + this.setState({ + DownloadType:true, + DownloadMessageval:500 + }) + } + }else { + this.props.showNotification(`正在下载中`); + window.open("/api"+url, '_blank'); + } + }).catch((error) => { + console.log(error) + }); + } + + toforums=(url)=>{ + window.open( url, '_blank'); + } + render() { + const Option = Select.Option; + let {max_support_count,data,ec_courses_list,editcourse,editnum,index,ec_year_id,Supportsclasskey,ecComponentState,hidesupport,supportid,Editkey,titlemessage,Supportstype,Supportslist,Supportssum,Supportsclass,major_school_id} = this.state; + var list = (length) => { + var res = []; + for(var i = 0; i < length; i++) { + res.push( +
                  支撑课程 +
                  (权值) +
                  +
                  ) + } + return res + } + + let toptiebox={width: 126.6*max_support_count+"px"}; + + let ismidbox={width:123.82*max_support_count+"px",margin:'0px 0px'}; + + // console.log(this.props.year&&this.props.year.can_manager) + return ( +
                  + +
                  +
                  {Supportslist}
                  +
                  + +
                  + + +
                  + + + +
                  + +
                  + 课程体系对毕业要求的支撑 + {/* 导出培养目标 */} + + + + this.confirmysl(`/ec_years/${this.props.match.params.ec_year_id}/graduation_course_supports.xlsx`)}>导出课程体系支撑矩阵 + +
                  用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 this.toforums(`/forums/${3534}`)} >查看详情
                  + +
                  +
                  + 毕业要求指标点({data.count} + 课程体系({data.course_count} +
                  + +
                  + +
                  + +

                  + 毕业要求指标点 + {data.graduation_subitems===undefined?"":list(max_support_count<5||max_support_count===undefined?5:max_support_count)} + 合计 +

                  +
                  + { + data.graduation_subitems===undefined? }/>:data.graduation_subitems.map((item,key)=>{ + + return ( +
                • + + {item.graduation_requirement_position+"-"+item.position} + + + + { + item.course_supports.map((t,kes)=>{ + + return( + +
                  {t.ec_course_name.length>12?t.ec_course_name.substring(0, 10)+"...":t.ec_course_name}
                  +
                  ({t.weights})
                  +
                  + ) + + }) + } + + +
                  +
                  +
                  {item.course_supports.length}
                  +
                  {Math.round(item.weights_total*100)/100===0?0:(Math.round(item.weights_total*100)/100)}
                  +
                  +
                  + {this.props.year&&this.props.year.can_manager===false?"": + + } +
                  +
                  + +
                  + + {Editkey===key? +

                  +

                  +

                  + 指标点 {index} + 支撑课程 + + 权重(∑=1) + (精确到两位小数) + + 关联度最高 +

                  + +
                  + {Supportsclass===true?:""} + { + editcourse.map((it,key)=>{ + + return( +
                  + + + + +
                  + +
                  + + + + +
                  + +
                  + {editcourse.length===1?"": + this.Deletcourses(key)}> + } + +
                  + +
                  + +
                  + ) + }) + } + +
                  + {Supportslist} +
                  + 合计: {editcourse.length} + 合计: {editnum} +
                  + +
                  +
                  保存
                  +
                  取消
                  +
                  +
                  +

                  :""} +
                • + ) + }) + } +
                  +
                  + +
                  +
                  + ); + } +} + +export default CourseSupports ; + diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js new file mode 100644 index 000000000..4ee387a73 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js @@ -0,0 +1,384 @@ +import React from 'react'; +import PropTypes from "prop-types"; +import { Link } from 'react-router-dom'; +import { Spin, Button, Input, Divider, Icon, Tooltip, Form, message, Modal } from 'antd'; +import axios from 'axios'; +import _ from 'lodash' + +import './index.scss'; + +const { confirm } = Modal; + +class GraduationRequirement extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + editIndex: null, + addState: false, + submitState: false, + validateState: false, + + currentEditReq: {}, + newRequirement: {}, + graduationRequirements: [] + } + } + + componentDidMount() { + this.getData(); + } + + getData = () => { + let { yearId } = this.props; + + this.setState({ loading: true }); + axios.get(`/ec_years/${yearId}/ec_graduation_requirements.json`).then(res => { + if(res.status === 200){ + this.setState({ + graduationRequirements: res.data.graduation_requirements, + loading: false + }) + } + }).catch(e => console.log(e)) + } + + showDeleteConfirm = (id) => { + if(this.state.editIndex !== null || this.state.addState){ + message.error('请先保存其它内容'); + return + } + confirm({ + title: '确认删除该毕业要求?', + okText: '确认', + cancelText: '取消', + onOk: () => { + this.deleteRequirement(id); + }, + onCancel() {}, + }); + } + + deleteRequirement = (id) => { + let { yearId } = this.props; + let url = `/ec_years/${yearId}/ec_graduation_requirements/${id}.json`; + axios.delete(url).then(res => { + if(res){ + message.success('操作成功'); + this.getData(); + } + }).catch(e => console.log(e)) + } + + showEditContent = (index) => { + let { editIndex, graduationRequirements } = this.state; + if(editIndex !== null){ + message.error('请先保存其它内容'); + return + } + + this.setState({ editIndex: index, currentEditReq: _.cloneDeep(graduationRequirements[index])}) + } + + onEditContentChange = (e) => { + let { currentEditReq } = this.state; + currentEditReq.content = e.target.value; + this.setState({ currentEditReq }); + } + + onEditItemContentChange = (e, index) => { + let { currentEditReq } = this.state; + currentEditReq.ec_graduation_subitems[index].content = e.target.value; + this.setState({ currentEditReq }); + } + + addEditItem = () => { + let { currentEditReq } = this.state; + currentEditReq.ec_graduation_subitems.push({id: null, content: ''}) + this.setState({ currentEditReq }); + } + + removeEditItem = (index) => { + let { currentEditReq } = this.state; + currentEditReq.ec_graduation_subitems.splice(index, 1); + this.setState({ currentEditReq }); + } + + saveContentEdit = () => { + let { currentEditReq } = this.state; + + let contentExist = currentEditReq.content && currentEditReq.content.length !== 0; + let errorItem = currentEditReq.ec_graduation_subitems.find(item => !item.content || item.content.length === 0); + this.setState({ validateState: !!errorItem || !contentExist }); + + if(errorItem || !contentExist){ return } + + this.setState({ submitState: true }, this.updateRequirement); + } + + cancelContentEdit = () => { + this.setState({ currentEditReq: {}, editIndex: null, validateState: false }); + } + + updateRequirement = () => { + let { yearId } = this.props; + let { currentEditReq } = this.state; + + let url = `/ec_years/${yearId}/ec_graduation_requirements/${currentEditReq.id}.json`; + + axios.put(url, { content: currentEditReq.content, position: currentEditReq.position, graduation_subitems: currentEditReq.ec_graduation_subitems }).then(res => { + if(res){ + message.success('操作成功'); + this.setState({ submitState: false, editIndex: null }); + this.getData(); + } + }).catch(e => { + console.log(e); + this.setState({ submitState: false }); + }) + } + + showNewReqContent = () => { + let { editIndex, graduationRequirements } = this.state; + if(editIndex !== null){ + message.error('请先保存其它内容'); + return + } + + this.setState({ + editIndex: -1, addState: true, + newRequirement: { + content: '', position: graduationRequirements.length + 1, + graduation_subitems: [ + { id: null, content: '' }, + { id: null, content: '' }, + { id: null, content: '' }, + ] + } + }) + } + + onNewReqContentChange = (e) => { + let { newRequirement } = this.state; + newRequirement.content = e.target.value; + this.setState({ newRequirement }); + } + + onNewReqItemContentChange = (e, index) => { + let { newRequirement } = this.state; + newRequirement.graduation_subitems[index].content = e.target.value; + this.setState({ newRequirement }); + } + + addNewReqItem = () => { + let { newRequirement } = this.state; + newRequirement.graduation_subitems.push({id: null, content: ''}) + this.setState({ newRequirement }); + } + + removeNewReqItem = (index) => { + let { newRequirement } = this.state; + newRequirement.graduation_subitems.splice(index, 1); + this.setState({ newRequirement }); + } + + saveNewReq = () => { + let { newRequirement } = this.state; + + let contentExist = newRequirement.content && newRequirement.content.length !== 0; + let errorItem = newRequirement.graduation_subitems.find(item => !item.content || item.content.length === 0); + this.setState({ validateState: !!errorItem || !contentExist }); + + if(errorItem || !contentExist){ return } + + this.setState({ submitState: true }, this.createRequirement); + } + + cancelNewReq = () => { + this.setState({ newRequirement: {}, addState: false, editIndex: null, validateState: false }); + } + + createRequirement = () => { + let { yearId } = this.props; + let { newRequirement } = this.state; + + let url = `/ec_years/${yearId}/ec_graduation_requirements.json`; + + axios.post(url, newRequirement).then(res => { + if(res){ + message.success('操作成功'); + this.setState({ submitState: false, editIndex: null, addState: false }); + this.getData(); + } + }).catch(e => { + console.log(e); + this.setState({ submitState: false }); + }) + } + + render() { + let { can_manager } = this.props.year; + let { loading, editIndex, addState, submitState, validateState, currentEditReq, graduationRequirements, newRequirement } = this.state; + + return ( +
                  + +
                  +
                  +
                  +
                  毕业要求(及其指标点)
                  +
                  + 请结合本专业特色修改毕业要求文字描述及指标点,需完全覆盖12项通用标准 + 查看详情 +
                  +
                  + 导出毕业要求 +
                  + + + +
                  +
                  +
                  +
                  指标点
                  +
                  内容
                  +
                  + { + can_manager && !addState && ( + + + + ) + } +
                  +
                  +
                  + { + graduationRequirements && graduationRequirements.map((item, index) => { + return can_manager && index === editIndex ? ( +
                  +
                  +
                  { index + 1 }
                  +
                  + + + +
                  +
                  + +
                  +
                  + { + currentEditReq.ec_graduation_subitems.map((subitem, i) => { + return ( +
                  +
                  { index + 1 }-{ i + 1 }
                  +
                  + + this.onEditItemContentChange(e, i)} /> + +
                  +
                  + this.removeEditItem(i)}/> +
                  +
                  + ) + }) + } + +
                  + + +
                  +
                  + ) : ( +
                  +
                  +
                  { index + 1 }
                  +
                  { item.content }
                  + { + can_manager && ( +
                  + this.showDeleteConfirm(item.id)} /> + this.showEditContent(index)}/> + { + index === graduationRequirements.length - 1 && !addState && ( + + ) + } +
                  + ) + } + +
                  + { + item.ec_graduation_subitems.map((subitem, i) => { + return ( +
                  +
                  { index + 1 }-{ i + 1 }
                  +
                  { subitem.content }
                  +
                  + ) + }) + } +
                  + ) + }) + } + + { + can_manager && addState && ( +
                  +
                  +
                  { graduationRequirements.length + 1 }
                  +
                  + + + +
                  +
                  + +
                  +
                  + { + newRequirement.graduation_subitems.map((subitem, i) => { + return ( +
                  +
                  { graduationRequirements.length + 1 }-{ i + 1 }
                  +
                  + + this.onNewReqItemContentChange(e, i)} /> + +
                  +
                  + this.removeNewReqItem(i)}/> +
                  +
                  + ) + }) + } + +
                  + + +
                  +
                  + ) + } +
                  +
                  +
                  +
                  +
                  +
                  + ) + } +} +GraduationRequirement.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.string, + yearId: PropTypes.string, +} + +export default GraduationRequirement \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss new file mode 100644 index 000000000..9d740a970 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss @@ -0,0 +1,94 @@ +.ec-graduation-requirement-page { + background: #fff; + + .graduation-requirement { + &-body { + margin-top: -24px; + } + + &-items { + &-head { + padding: 15px 30px; + display: flex; + background: #F5F5F5; + } + + &-body { + margin: 0 30px; + + &-item { + padding: 10px 0px; + border-bottom: 1px solid #eaeaea; + + &.active { + .item-row { + margin-bottom: 10px; + align-items: center; + } + + .item-column-operation { + width: 40px; + } + } + + &:last-child { + border-bottom: unset; + } + + .item-head { + margin-bottom: 10px; + font-weight: bold; + } + + .item-row { + display: flex; + } + } + } + + + .no-column { + width: 60px; + text-align: center; + } + + .item-content-column { + flex: 1; + padding-left: 10px; + display: flex; + + .ant-form-item { + flex: 1; + margin-bottom: 0; + } + } + + .item-column-operation { + display: flex; + justify-content: flex-end; + width: 80px; + + & > i { + margin: 0 5px; + font-size: 16px; + cursor: pointer; + } + } + } + } + + .edit-form { + margin-top: 10px; + text-align: right; + + button { + margin-left: 10px; + } + } + + i.edit-action { + color: #29BD8B; + cursor: pointer; + font-size: 16px; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js new file mode 100644 index 000000000..e48cf2c84 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js @@ -0,0 +1,264 @@ +import React from 'react'; +import PropTypes from "prop-types"; +import { Link } from 'react-router-dom'; +import { Spin, Button, Input, Divider, Icon, Tooltip, Form, message } from 'antd'; +import axios from 'axios'; + +import './index.scss'; + +class TrainingObjective extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + contentEditState: false, + itemsEditState: false, + submitState: false, + validateState: false, + itemSubmitState: false, + itemValidateState: false, + + objective: {}, + editContent: '', + trainingSubitems: [] + } + } + + componentDidMount() { + this.getData(); + } + + getData = () => { + let { yearId } = this.props; + + axios.get(`/ec_years/${yearId}/ec_training_objectives.json`).then(res => { + if(res.status === 200){ + this.setState({ + objective: res.data, + editContent: res.data.content, + trainingSubitems: res.data.ec_training_items, + loading: false + }) + } + }).catch(e => console.log(e)) + } + + saveContentEdit = () => { + let { editContent } = this.state; + this.setState({ validateState: editContent.length === 0 }); + if(editContent.length === 0){ return; } + + this.setState( + { submitState: true }, + () => { + this.updateTrainingObjective( + { content: editContent }, + () => { + this.setState({ submitState: false, contentEditState: false }); + this.getData(); + }, + _e => { + this.setState({ submitState: false }) + } + ) + } + ); + } + + cancelContentEdit = () => { + this.setState({ editContent: this.state.objective.content, contentEditState: false }); + } + + editItemsContent = () => { + let { trainingSubitems } = this.state; + if(!trainingSubitems || trainingSubitems.length === 0){ + trainingSubitems = [{ id: null, content: null }] + } + this.setState({ trainingSubitems: trainingSubitems, itemsEditState: true }); + } + + addItemColumn = (index) => { + let { trainingSubitems } = this.state; + trainingSubitems.splice(index, 0, { id: null, content: null }); + this.setState({ trainingSubitems }) + } + + removeItemColumn = (index) => { + let { trainingSubitems } = this.state; + trainingSubitems.splice(index, 1); + this.setState({ trainingSubitems }) + } + + onItemContentChange = (e, index) => { + let { trainingSubitems } = this.state; + trainingSubitems[index].content = e.target.value; + + this.setState({ trainingSubitems: trainingSubitems }); + } + + saveItemsContentEdit = () => { + let { objective, trainingSubitems } = this.state; + + let errorItem = trainingSubitems.find(item => !item.content || item.content.length === 0); + this.setState({ itemValidateState: !!errorItem }); + + if(errorItem){ return } + + this.setState( + { itemSubmitState: true }, + () => { + this.updateTrainingObjective( + { content: objective.content, training_subitems: trainingSubitems }, + () => { + this.setState({ itemSubmitState: false, itemsEditState: false }); + this.getData(); + }, + _e => { + this.setState({ itemSubmitState: false }) + } + ) + } + ); + } + + cancelItemsContentEdit = () => { + this.setState({ trainingSubitems: this.state.objective.ec_training_items, itemsEditState: false, itemValidateState: false }); + } + + updateTrainingObjective = (data, success, fail) => { + let { yearId } = this.props; + let url = `/ec_years/${yearId}/ec_training_objectives.json`; + + axios.post(url, data).then(res => { + if(res){ + message.success('操作成功'); + success(); + } + }).catch(e => { + console.log(e); + fail(e); + }) + } + + render() { + let { can_manager } = this.props.year; + let { loading, contentEditState, itemsEditState, objective, editContent, trainingSubitems, validateState, itemValidateState, itemSubmitState, submitState } = this.state; + + return ( +
                  + +
                  +
                  +
                  +
                  培养目标
                  +
                  + 请结合本专业特色修改培养目标文字描述及目标分解查看详情 + 查看详情 +
                  +
                  + 导出培养目标 +
                  + + + +
                  + { + can_manager && contentEditState ? ( +
                  +
                  + + this.setState({ editContent: e.target.value })} /> + +
                  +
                  + + +
                  +
                  + ) : ( +
                  +
                  { objective.content }
                  + { + can_manager && ( +
                  + + this.setState({ contentEditState: true })} /> + +
                  + ) + } +
                  + ) + } + +
                  +
                  +
                  分项
                  +
                  目标分解详情
                  +
                  + { + !can_manager || itemsEditState || ( + + + + ) + } +
                  +
                  +
                  + { + can_manager && itemsEditState ? ( +
                  + { + trainingSubitems && trainingSubitems.map((item, index) => { + return ( +
                  +
                  {index + 1}
                  +
                  + + this.onItemContentChange(e, index)} /> + +
                  + { index !== 0 && this.removeItemColumn(index)} /> } + + this.addItemColumn(index + 1)} style={{ color: '#29BD8B' }} /> +
                  +
                  +
                  + ) + }) + } + +
                  + + +
                  +
                  + ) : ( + objective.ec_training_items && objective.ec_training_items.map((item, index) => { + return ( +
                  +
                  { index + 1 }
                  +
                  { item.content }
                  +
                  + ) + }) + ) + } +
                  +
                  +
                  +
                  +
                  +
                  + ) + } +} +TrainingObjective.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.string, + yearId: PropTypes.string, +} + +export default TrainingObjective \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss new file mode 100644 index 000000000..50b801459 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss @@ -0,0 +1,99 @@ +.ec-training-objective-page { + background: #ffffff; + + .training-objective { + &-body { + margin-top: -24px; + min-height: 600px; + } + + &-content { + display: flex; + padding: 20px 30px; + line-height: 2.0; + + &.block { + display: block; + } + + &-text { + flex: 1; + } + + &-edit { + margin-left: 20px; + + & > i { + color: #29BD8B; + cursor: pointer; + font-size: 18px; + } + } + + &-form { + margin-top: 10px; + text-align: right; + + button { + margin-left: 10px; + } + } + } + + &-items { + &-head { + padding: 15px 30px; + display: flex; + background: #F5F5F5; + } + + &-body { + margin: 0 30px; + + &-item { + display: flex; + min-height: 48px; + padding: 10px 0px; + border-bottom: 1px solid #eaeaea; + + &:last-child { + border-bottom: unset; + } + } + } + + .no-column { + width: 40px; + text-align: center; + } + + .item-content-column { + flex: 1; + padding-left: 10px; + display: flex; + + .ant-form-item { + flex: 1; + margin-bottom: 0; + } + + .item-column-operation { + display: flex; + justify-content: flex-end; + width: 80px; + + & > i { + margin: 15px 10px; + font-size: 18px; + } + } + } + } + } + + i.edit-action { + color: #29BD8B; + cursor: pointer; + font-size: 18px; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js new file mode 100644 index 000000000..d85d10aec --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -0,0 +1,148 @@ +import React from 'react'; +import { Switch, Route, Link } from 'react-router-dom'; +import { Steps, Breadcrumb } from 'antd'; +import axios from 'axios'; + +import './index.scss'; + +import CustomLoadable from "../../../CustomLoadable"; +import Loadable from 'react-loadable'; +import Loading from "../../../Loading"; +const { Step } = Steps; +const steps = ["培养目标", "毕业要求", "培养目标VS毕业要求", "毕业要求VS通用标准", "学生", "课程体系", "课程体系VS毕业要求", "达成度评价结果"]; +const stepTypes = ["training_objectives", "graduation_requirement", "requirement_vs_objective", "requirement_vs_standard", "students", "courses", "requirement_vs_courses", "reach_calculation_info"]; +const EcStudentList=Loadable({ + loader: () => import('../subroute/ecStudentList/EcStudentList'), + loading: Loading, +}); +const Curriculum=Loadable({ + loader: () => import('../../../modules/ecs/curriculum/Curriculum'), + loading: Loading, +}); +const TrainingObjective=Loadable({ + loader: () => import('./TrainingObjective/index'), + loading: Loading, +}); +const GraduationRequirement=Loadable({ + loader: () => import('./GraduationRequirement/index'), + loading: Loading, +}); +const CourseSupports=Loadable({ + loader: () => import('./CourseSupports/index'), + loading: Loading, +}); + +class EcSetting extends React.Component { + constructor (props) { + super(props); + + this.state = { + schoolId: null, + majorId: props.match.params.majorId, + yearId: props.match.params.yearId, + year: null, + + stepIndex: 0, + } + } + + componentDidMount() { + this.setupStep(); + this.getYearDetail(); + } + + getYearDetail = () => { + let { majorId, yearId } = this.state; + axios.get(`/ec_major_schools/${majorId}/ec_years/${yearId}.json`).then(res => { + if(res){ + this.setState({ year: res.data, schoolId: res.data.school_id }) + } + }).catch(e => console.log(e)) + } + + onStepChange = (stepIndex) => { + let { majorId, yearId } = this.state; + let type = stepTypes[stepIndex]; + + this.setState({ stepIndex: stepIndex }); + if(type==="courses"){ + this.props.history.push(`/ecs/major_schools/${majorId}/years/${yearId}/${type}/ec_course_support_setting/1`); + }else { + this.props.history.push(`/ecs/major_schools/${majorId}/years/${yearId}/${type}`); + } + } + + setupStep = () => { + let type = this.props.match.params.type; + + let stepIndex = stepTypes.indexOf(type); + this.setState({ stepIndex: stepIndex }); + } + + render() { + let { year, schoolId, majorId, yearId } = this.state; + let { stepIndex } = this.state; + + return ( +
                  +
                  +
                  + + + { year && year.school_name } + + + { year && year.major_name } + + {year && year.year}届 + +
                  + +
                  + + + { + steps.map((title, index) => { + return ( + + ) + }) + } + +
                  + + { + year && ( + + () }> + () }> + + + {/*学生*/} + () }> + {/*课程体系*/} + () }> + {/*课程体系VS毕业要求*/} + () }> + + + + + ) + } +
                  +
                  + ) + } +} + +export default EcSetting \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/index.scss b/public/react/src/modules/ecs/EcSetting/index.scss new file mode 100644 index 000000000..7fcd80880 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/index.scss @@ -0,0 +1,62 @@ +.ec-page { + margin-bottom: 50px; + + .ec-breadcrumb { + margin-top: 10px; + margin-bottom: 10px; + } + + .ec-steps { + &-box { + margin-bottom: 10px; + padding-left: 20px; + padding-right: 20px; + justify-content: space-between; + background: #fff; + + .ant-steps-item { + flex: unset !important; + + &-container { + margin-left: 0; + } + + &.ant-steps-item-active { + .ant-steps-item-subtitle { + color: #1890ff; + } + } + + &-subtitle { + margin-left: 0; + margin-right: 8px; + } + } + } + } + + .ec-head { + margin-bottom: -24px; + padding: 20px 30px; + display: flex; + align-items: flex-end; + justify-content: space-between; + + &-left { + flex: 1; + } + + &-label { + font-size: 18px; + } + + &-tip { + font-size: 14px; + color: #999999; + } + } + + .link { + color: #007bff; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/AddYearModal.js b/public/react/src/modules/ecs/EcYear/AddYearModal.js new file mode 100644 index 000000000..e54ba6b73 --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/AddYearModal.js @@ -0,0 +1,108 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Modal, Select, message } from 'antd'; +import axios from 'axios'; + +import './AddYearModal.scss'; + +const { Option } = Select; + +class AddYearModal extends React.Component { + constructor(props) { + super(props); + + this.state = { + confirmLoading: false, + error: '', + + year: '', + currentYear: new Date().getFullYear() + } + } + + handleOk = () => { + let { year } = this.state; + + if(!year || year.length === 0){ + this.setState({ error: '请选择届别' }); + return; + } + + this.submitYear(); + } + + handleCancel = () => { + this.props.onHide(false); + } + + onAfterModalClose = () => { + this.setState({ year: '' }); + } + + submitYear = () => { + let { schoolId, majorId } = this.props; + let { year } = this.state; + + this.setState({ confirmLoading: true }); + axios.post(`/ec_major_schools/${majorId}/ec_years.json`, { school_id: schoolId, year: year }).then(res => { + if(res.status === 200){ + message.success('操作成功'); + this.setState({ confirmLoading: false }); + this.props.onHide(true); + } + }).catch(e => { + console.log(e); + this.setState({ confirmLoading: false }); + }) + } + + render() { + let { confirmLoading, year, currentYear } = this.state; + + return ( +
                  + + +
                  +
                  + 基础数据:除学生列表与成绩录入以外的所有基础数据
                  + 将自动复制上届别的数据;数据均可再编辑 +
                  + +
                  +
                  选择届别:
                  +
                  + +
                  +
                  +
                  +
                  +
                  + ) + } +} + +AddYearModal.propTypes = { + schoolId: PropTypes.number, + majorId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddYearModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/AddYearModal.scss b/public/react/src/modules/ecs/EcYear/AddYearModal.scss new file mode 100644 index 000000000..75218677d --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/AddYearModal.scss @@ -0,0 +1,34 @@ +.add-year-modal { + .add-year { + &-container { + padding: 0 40px; + } + + &-tip { + margin-bottom: 20px; + color: #666666; + line-height: 30px; + text-align: center; + } + + &-content { + padding: 0 50px; + display: flex; + align-items: center; + + &-label { + + } + + &-select { + flex: 1; + } + } + } + + .ant-modal-footer { + padding-bottom: 20px; + text-align: center; + border-top: unset; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/index.js b/public/react/src/modules/ecs/EcYear/index.js new file mode 100644 index 000000000..e9d3a0296 --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/index.js @@ -0,0 +1,218 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import { Spin, Button, Table, Input, Divider, Modal, message, Breadcrumb } from 'antd'; + +import './index.scss'; +import AddYearModal from "./AddYearModal"; + +const { Search } = Input; +const { confirm } = Modal; + +const defaultPagination = { current: 1, pageSize: 20, total: 0 }; + + +class EcYear extends React.Component { + constructor (props) { + super(props); + + this.state = { + majorId: props.match.params.majorId, + + spin: true, + loading: true, + keyword: '', + pagination: {...defaultPagination}, + + major: {}, + yearData: [], + + // add year modal vars + addYearModalVisible: false + } + } + + componentDidMount() { + this.getMajor(); + } + + getMajor = () => { + axios.get(`/ec_major_schools/${this.state.majorId}.json`).then(res => { + if(res.status === 200){ + window.document.title = res.data.name; + this.setState({ spin: false, major: res.data }); + this.getYearData(); + } + }).catch(e => console.log(e)); + } + + onSearch = () => { + this.setState({ pagination: {...defaultPagination} }, () => { + this.getYearData(); + }) + } + + getYearData = () => { + let { majorId, keyword, pagination } = this.state; + axios.get(`/ec_major_schools/${majorId}/ec_years.json`, { + params: { + search: keyword, + page: pagination.current, + per_page: pagination.pageSize + } + }).then(res => { + if(res.status === 200){ + let pagination = { ...this.state.pagination }; + pagination.total = res.data.count; + + this.setState({ + loading: false, + yearData: res.data.ec_years, + pagination + }) + } + }).catch((e) => { + console.log(e); + this.setState({ loading: false }); + }) + } + + onPaginationChange = (page, pageSize) => { + this.setState({ pagination: { current: page, pageSize: pageSize } }, () => { + this.getYearData() + }); + } + + showDeleteYearConfirm = (yearId) => { + confirm({ + title: '确认删除该届别?', + okText: '确认', + cancelText: '取消', + onOk: () => { + this.deleteYear(yearId); + }, + onCancel() {}, + }); + } + + deleteYear = (yearId) => { + let { majorId } = this.state; + axios.delete(`/ec_major_schools/${majorId}/ec_years/${yearId}.json`).then(res => { + if(res.status === 200){ + message.success('操作成功'); + this.getYearData(); + } + }).catch(e => console.log(e)) + } + + HideAddYearModal = (added) => { + this.setState({ AddYearModalVisible: false }); + if(added){ + this.setState({ keyword: '', pagination: { ...defaultPagination } }, this.getYearData); + } + } + + render() { + let { majorId, spin, keyword, loading, pagination, major, yearData } = this.state; + + const linkRender = (num, url) => { + return { num === 0 ? "立即配置" : num }; + } + const contrastRender = (num, other) => { + let color = other !== 0 && num === other ? 'color-green' : 'color-orange'; + + return other === 0 ? ( +
                  -- / --
                  + ) : ( +
                  {num} / {other}
                  + ) + } + const statusRender = (text, record) => { + let zero = record.graduation_subitem_count === 0; + + return zero ? ( + -- + ) : ( + + { text === 'achieved' ? '已达成' : '未达成' } + + ) + } + const operationRender = (_, record) => { + return ( + + ) + } + const tableColumns = [ + { title: '届别', dataIndex: 'year', render: text => `${text}届` }, + { title: '培养目标', dataIndex: 'training_subitem_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/training_objectives`), }, + { title: '毕业要求', dataIndex: 'graduation_requirement_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/graduation_requirement`), }, + { title: '课程体系', dataIndex: 'course_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/ec_course_setting`), }, + { title: '课程目标(达成情况)', key: 'courseTarget', render: (_, record) => { return contrastRender(record.achieved_graduation_course_count, record.course_target_count) } }, + { title: '毕业要求指标点(达成情况)', key: 'graduation', render: (_, record) => { return contrastRender(record.achieved_graduation_objective_count, record.graduation_subitem_count) } }, + { title: '评价结果', dataIndex: 'status', render: statusRender }, + { title: '操作', key: 'operation', render: operationRender } + ]; + + return ( +
                  + +
                  +
                  + + + { major && major.school_name } + + { major && major.name } + +
                  + +
                  +
                  +
                  +
                  { major.name }
                  +
                  + 请选择添加参与认证的学生界别,多个界别分次添加 + 查看详情 +
                  +
                  + +
                  + + + +
                  +
                  + this.setState({keyword: e.target.value})} + onSearch={this.onSearch} + value={keyword} + style={{ width: 200 }}/> +
                  + +
                  +
                  + + + + + + + + + ) + } +} + +export default EcYear; \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/index.scss b/public/react/src/modules/ecs/EcYear/index.scss new file mode 100644 index 000000000..66f49e304 --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/index.scss @@ -0,0 +1,62 @@ +.ec-year-list-page { + .ec-breadcrumb { + margin-top: 10px; + margin-bottom: 10px; + } + + .ec-year-list-container { + background: #fff; + } + + .year-list { + &-head { + margin-bottom: -24px; + padding: 20px 30px; + display: flex; + align-items: flex-end; + justify-content: space-between; + + &-left { + flex: 1; + } + + &-label { + font-size: 18px; + } + + &-tip { + font-size: 14px; + color: #999999; + } + } + + + &-body { + margin-top: -24px; + } + + &-search { + padding: 20px 30px; + display: flex; + flex-direction: row-reverse; + } + + &-table { + min-height: 400px; + + th, td { + text-align: center; + } + } + } + + .link { + color: #007bff; + } + + .operation-box { + .link { + margin: 0 5px; + } + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Ecs.js b/public/react/src/modules/ecs/Ecs.js new file mode 100644 index 000000000..dab84e8d5 --- /dev/null +++ b/public/react/src/modules/ecs/Ecs.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { Switch, Route } from 'react-router-dom'; +import { SnackbarHOC } from 'educoder'; + +import CustomLoadable from "../../CustomLoadable"; +import {TPMIndexHOC} from "../tpm/TPMIndexHOC"; + +const Home = CustomLoadable(() => import('./Home/index')); +const EcYear = CustomLoadable(() => import('./EcYear/index')); +const EcSetting = CustomLoadable(() => import('./EcSetting/index')); + +class Ecs extends React.Component { + + render() { + return ( +
                  + + + + + +
                  + ) + } +} + +export default SnackbarHOC() (TPMIndexHOC ( Ecs )); \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddMajorModal.js b/public/react/src/modules/ecs/Home/AddMajorModal.js new file mode 100644 index 000000000..9b58ed7e4 --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddMajorModal.js @@ -0,0 +1,179 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Modal, Input, Table, message } from 'antd'; +import axios from 'axios'; + +import './AddMajorModal.scss'; + +const { Search } = Input; +const tableColumns = [ + { title: '专业代码', dataIndex: 'code', key: 'code', width: 100, }, + { title: '专业名称', dataIndex: 'name', key: 'name', }, + { title: '', dataIndex: 'selected', key: 'selected', width: 80, render: selected => selected && 已选择 }, +]; +const defaultPagination = { current: 1, pageSize: 10, total: 0 }; + +class AddMajorModal extends React.Component { + constructor(props) { + super(props); + + this.state = { + loading: false, + confirmLoading: false, + error: '', + keyword: '', + pagination: {...defaultPagination}, + + schoolId: props.schoolId, + majorData: [], + selectedData: [] + } + + this.getMajors = this.getMajors.bind(this); + this.selectMajor = this.selectMajor.bind(this); + this.onAfterModalClose = this.onAfterModalClose.bind(this); + this.handleOk = this.handleOk.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.onPaginationChange = this.onPaginationChange.bind(this); + } + + componentDidUpdate(prevProps) { + if(!prevProps.visible && this.props.visible){ + this.getMajors(); + } + } + + onSearch = () => { + this.setState({ pagination: {...defaultPagination} }, () => { + this.getMajors(); + }) + } + + getMajors(){ + let { schoolId, keyword, pagination } = this.state; + + this.setState({ loading: true }); + axios.get(`/schools/${schoolId}/ec_majors.json`, { + params: { + search: keyword, + page: pagination.current, + per_page: pagination.pageSize + } + }).then(res => { + if(res.status === 200){ + let pagination = { ...this.state.pagination }; + pagination.total = res.data.count; + + this.setState({ + majorData: res.data.ec_majors, + loading: false, + pagination, + }) + } + }).catch(e => { + console.log(e); + this.setState({ loading: false }) + }) + } + + getCheckboxProps(record){ + return { ...record, disabled: record.selected } + } + + selectMajor(selectedRowKeys){ + this.setState({ selectedData: selectedRowKeys }); + } + + onPaginationChange(page, pageSize){ + this.setState({ pagination: { current: page, pageSize: pageSize } }, () => { + this.getMajors() + }); + } + + handleOk(){ + let { selectedData } = this.state; + + if(selectedData.length === 0){ + this.setState({ error: '请选择专业' }); + return; + } + + this.submitMajor(selectedData); + } + + handleCancel(){ + this.props.onHide(false); + } + + onAfterModalClose(){ + this.setState({ + error: '', + keyword: '', + pagination: {...defaultPagination}, + majorData: [], + selectedData: [], + }); + } + + submitMajor(ids) { + let { schoolId } = this.state; + + this.setState({ confirmLoading: true }); + axios.post(`/schools/${schoolId}/ec_major_schools.json`, { major_ids: ids }).then(res => { + if(res.status === 200){ + message.success('操作成功'); + this.setState({ confirmLoading: false }); + this.props.onHide(true); + } + }).catch(e => { + console.log(e); + this.setState({ confirmLoading: false }); + }) + } + + render() { + let { loading, keyword, majorData, selectedData, pagination } = this.state; + + return ( +
                  + + +
                  + this.setState({keyword: e.target.value})} + onSearch={this.onSearch} + value={keyword}/> +
                  + +
                  +
                  +
                  { this.state.error }
                  + + + + ) + } +} + +AddMajorModal.propTypes = { + schoolId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddMajorModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddMajorModal.scss b/public/react/src/modules/ecs/Home/AddMajorModal.scss new file mode 100644 index 000000000..bde678bcd --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddMajorModal.scss @@ -0,0 +1,29 @@ +.add-major-modal { + .add-major-search { + margin-bottom: 20px; + } + .ant-modal-body { + padding-bottom: 0; + + .major-row { + padding: 10px; + } + .ant-table-thead { + background: #fafafa; + } + .ant-table-scroll { + min-height: 250px; + } + + .error { + height: 20px; + margin-top: -20px; + color: red; + } + } + .ant-modal-footer { + padding-bottom: 20px; + text-align: center; + border-top: unset; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.js b/public/react/src/modules/ecs/Home/AddManagerModal.js new file mode 100644 index 000000000..7e341ea11 --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddManagerModal.js @@ -0,0 +1,226 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Modal, Input, Table, message, Select, Form, Row, Col, Button } from 'antd'; +import axios from 'axios'; + +import './AddManagerModal.scss'; + +const { Option } = Select; + +const columnRender = (text) =>
                  {text}
                  +const tableColumns = [ + { title: '姓名', dataIndex: 'name', key: 'name', width: 60, render: columnRender }, + { title: '职称', dataIndex: 'identity', key: 'identity', width: 60, }, + { title: '单位', dataIndex: 'school_name', key: 'school_name', render: (_, record) => columnRender(`${record.school_name} ${record.department_name}`) }, + { title: '手机号', dataIndex: 'phone', key: 'phone', width: 80, }, +]; +const defaultPagination = { current: 1, pageSize: 20, total: 0 }; + +class AddManagerModal extends React.Component { + constructor(props) { + super(props); + + this.state = { + loading: false, + confirmLoading: false, + nameValidateStatus: '', + error: '', + name: '', + school: props.schoolName, + identity: '', + pagination: {...defaultPagination}, + + schoolId: props.schoolId, + userData: [], + selectedData: [] + } + + this.getUsers = this.getUsers.bind(this); + this.selectUser = this.selectUser.bind(this); + this.onAfterModalClose = this.onAfterModalClose.bind(this); + this.handleOk = this.handleOk.bind(this); + this.handleCancel = this.handleCancel.bind(this); + this.onPaginationChange = this.onPaginationChange.bind(this); + } + + onSearch = () => { + this.setState({ pagination: {...defaultPagination} }, () => { + this.getUsers(); + }) + } + + getUsers(){ + let { majorId } = this.props; + let { name, school, identity, pagination } = this.state; + + if(name.length === 0){ + this.setState({ nameValidateStatus: 'error' }); + return; + } + + this.setState({ loading: true }); + axios.get(`/ec_major_schools/${majorId}/users.json`, { + params: { + name, school, identity, + page: pagination.current, + per_page: pagination.pageSize + } + }).then(res => { + if(res.status === 200){ + let pagination = { ...this.state.pagination }; + pagination.total = res.data.count; + + this.setState({ + userData: res.data.users, + loading: false, + pagination, + }) + } + }).catch(e => { + console.log(e); + this.setState({ loading: false }) + }) + } + + getCheckboxProps(record){ + return { ...record, disabled: record.manager } + } + + selectUser(selectedRowKeys){ + this.setState({ selectedData: selectedRowKeys }); + } + + onPaginationChange(page, pageSize){ + this.setState({ pagination: { current: page, pageSize: pageSize } }, () => { + this.getUsers() + }); + } + + onNameChange = (e) => { + let name = e.target.value; + let nameValidateStatus = ''; + + if(name.length === 0){ + nameValidateStatus = 'error' + } + + this.setState({ nameValidateStatus, name }); + } + + handleOk(){ + this.setState({ error: '' }); + let { selectedData } = this.state; + + if(selectedData.length === 0){ + this.setState({ error: '请选择至少一个用户' }); + return; + } + + this.submitUsers(selectedData); + } + + handleCancel(){ + this.props.onHide(false); + } + + onAfterModalClose(){ + this.setState({ + error: '', + nameValidateStatus: '', + name: '', + school: this.props.schoolName, + identity: '', + pagination: {...defaultPagination}, + userData: [], + selectedData: [], + }); + } + + submitUsers(ids) { + let { majorId } = this.props; + + this.setState({ confirmLoading: true }); + axios.post(`/ec_major_schools/${majorId}/major_managers.json`, { user_ids: ids }).then(res => { + if(res.status !== 200){ return } + + message.success('操作成功'); + this.setState({ confirmLoading: false }); + this.props.onHide(true); + }).catch(e => { + console.log(e); + this.setState({ confirmLoading: false }); + }) + } + + render() { + let { loading, name, school, identity, userData, selectedData, pagination, nameValidateStatus } = this.state; + + return ( +
                  + + +
                  +
                  + +
                  + + + + + + + + + + + + + + this.setState({ school: e.target.value })} value={school} placeholder="请输入学校名称"/> + + + + + + + + + +
                  +
                  +
                  { this.state.error }
                  + + + + ) + } +} + +AddManagerModal.propTypes = { + schoolId: PropTypes.string, + schoolName: PropTypes.string, + majorId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddManagerModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.scss b/public/react/src/modules/ecs/Home/AddManagerModal.scss new file mode 100644 index 000000000..2b30690fc --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddManagerModal.scss @@ -0,0 +1,35 @@ +.add-ec-manager-modal { + .ant-modal-body { + padding-bottom: 0; + + .ant-table-thead { + background: #fafafa; + } + .ant-table-scroll { + min-height: 250px; + } + + .add-ec-manager-search { + margin-bottom: 20px; + + .ant-form-item { + margin-bottom: 0; + + &-label > label { + font-size: 14px !important; + } + } + } + + .error { + height: 20px; + margin-top: -20px; + color: red; + } + } + .ant-modal-footer { + padding-bottom: 20px; + text-align: center; + border-top: unset; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/MajorManager.js b/public/react/src/modules/ecs/Home/MajorManager.js new file mode 100644 index 000000000..37b9d6e49 --- /dev/null +++ b/public/react/src/modules/ecs/Home/MajorManager.js @@ -0,0 +1,60 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Tag, message } from 'antd'; +import axios from 'axios'; + +class MajorManager extends React.Component { + constructor(props) { + super(props); + + this.state = { + schoolId: props.schoolId, + majorId: props.majorId, + canManage: props.canManage, + managers: props.managers + } + + this.deleteManager = this.deleteManager.bind(this); + } + + componentDidUpdate(prevProps) { + if(this.props.managers.length !== prevProps.managers.length){ + this.setState({ managers: this.props.managers }); + } + } + + deleteManager(managerId){ + axios.delete(`/ec_major_schools/${this.state.majorId}/major_managers/${managerId}.json`).then(result => { + if(result.status === 200){ + message.success('操作成功'); + } + }).catch(e => { console.log(e) }) + } + + render() { + let { canManage, managers } = this.state; + + return ( +
                  + { + managers && managers.map(manager => { + return ( + { this.deleteManager(manager.id) }} color="blue"> + { manager.name } + + ) + }) + } +
                  + ) + } +} + +MajorManager.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.number, + canManage: PropTypes.bool, + managers: PropTypes.array +} + +export default MajorManager \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/index.js b/public/react/src/modules/ecs/Home/index.js new file mode 100644 index 000000000..8f66b6572 --- /dev/null +++ b/public/react/src/modules/ecs/Home/index.js @@ -0,0 +1,265 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Spin, Avatar, Tooltip, Button, Divider, Input, Row, Col, Icon, Modal } from "antd"; +import { getImageUrl } from 'educoder'; +import axios from 'axios'; + +import './index.scss'; +import bgImage from '../../../images/ecs/bg.jpg'; + +import MajorManager from "./MajorManager"; +import AddMajorModal from "./AddMajorModal"; +import AddManagerModal from "./AddManagerModal"; + +const { Search } = Input; +const { confirm } = Modal; + +class Home extends React.Component { + constructor (props) { + super(props); + + const searchParams = new URLSearchParams(props.location.search.substring(1)); + let schoolId = searchParams.get('school_id'); + + if(!schoolId){ + this.props.history.push(`/nopage`); + return; + } + + this.state = { + loading: true, + majorLoading: true, + AddMajorVisible: false, + AddManagerVisible: false, + searchKeyword: '', + + schoolId: schoolId, + currentMajorId: null, + school: null, + currentUser: null, + managers: null, + templateMajor: null, + majors: null, + majorCount: 0 + } + + this.getSchoolMajors = this.getSchoolMajors.bind(this); + this.HideAddMajorModal = this.HideAddMajorModal.bind(this); + this.showDeleteMajorConfirm = this.showDeleteMajorConfirm.bind(this); + this.showAddManagerModal = this.showAddManagerModal.bind(this); + this.HideAddManagerModal = this.HideAddManagerModal.bind(this); + } + + componentDidMount() { + this.getSchoolDetail(); + } + + getSchoolDetail() { + axios.get(`/schools/${this.state.schoolId}/detail.json`).then(result => { + if(result.status === 200){ + window.document.title = result.data.school.name; + this.setState({ + school: result.data.school, + currentUser: result.data.current_user, + managers: result.data.school_managers, + loading: false + }); + this.getSchoolMajors(); + } + }).catch(e => { + console.log(e); + this.setState({ loading: false }); + }); + } + + getSchoolMajors(){ + let that = this; + let keyword = this.state.searchKeyword; + this.setState({ majorLoading: true }); + + axios.get(`/schools/${this.state.schoolId}/ec_major_schools.json?search=${keyword}&per_page=50`).then(result => { + if(result.status === 200){ + that.setState({ + majorCount: result.data.count, + templateMajor: result.data.template_ec_major_school, + majors: result.data.ec_major_schools, + majorLoading: false + }); + } + }).catch(e => { + console.log(e); + that.setState({ majorLoading: false }); + }); + } + + showAddManagerModal(majorId){ + this.setState({ currentMajorId: majorId, AddManagerVisible: true }); + } + + HideAddMajorModal(added){ + this.setState({ AddMajorVisible: false }); + if(added){ + this.setState({ searchKeyword: '' }, this.getSchoolMajors) + } + } + HideAddManagerModal(added){ + this.setState({ AddManagerVisible: false }); + if(added){ + this.setState({ searchKeyword: '' }, this.getSchoolMajors) + } + } + + showDeleteMajorConfirm(majorId){ + confirm({ + title: '确认删除该认证专业?', + okText: '确认', + cancelText: '取消', + onOk: () => { + this.deleteMajor(majorId); + }, + onCancel() {}, + }); + } + + deleteMajor(majorId){ + let { schoolId, majorCount, majors } = this.state; + axios.delete(`/schools/${schoolId}/ec_major_schools/${majorId}.json`).then(res => { + if(res.status === 200){ + this.setState({ + majorCount: majorCount - 1, + majors: majors.filter(major => major.id !== majorId) + }); + } + }).catch(e => console.log(e)) + } + + render() { + let { currentUser, school, managers, templateMajor, majors, majorCount } = this.state; + + const manageSchool = !!currentUser && (currentUser.manager || currentUser.admin); + const manageMajor = !!currentUser && (manageSchool || currentUser.major_manager); + + const configBtnText = manageMajor ? '配置' : '查看'; + + return ( +
                  + +
                  +
                  +
                  + { school && school.name } +
                  +
                  + +
                  +
                  +
                  学校管理员
                  +
                  温馨提醒:学校管理员有添加专业及设置专业管理员等权限
                  +
                  +
                  + { + managers && managers.map((manager) => { + return ( + + + + { manager.name } + + + ) + }) + } +
                  +
                  + +
                  +
                  +
                  +
                  专业列表
                  +
                  + 请添加参与认证的专业名称 + 查看详情 +
                  +
                  + +
                  + + + +
                  +
                  +
                  {majorCount || 0} 个检索结果({majorCount || 0} 专业)
                  + this.setState({searchKeyword: e.target.value})} + onSearch={this.getSchoolMajors} + value={this.state.searchKeyword} + style={{ width: 200 }} + /> +
                  +
                  + +
                  序号 + 专业代码 + 专业名称 + 专业管理员 + 操作 + + + { + templateMajor && ( + + 0 + 000000 + + { templateMajor.name } + + + + { configBtnText } + + + ) + } + { + majors && majors.map((major, index) => { + return ( + + { index + 1 } + { major.code } + + { major.name } + + +
                  + { manageMajor && this.showAddManagerModal(major.id)}> } + + +
                  + + + { configBtnText } + { manageSchool && ( this.showDeleteMajorConfirm(major.id)}>删除 ) } + + + ) + }) + } + + + + + + + + { this.state.school && } + + + ) + } +} + +export default Home; \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/index.scss b/public/react/src/modules/ecs/Home/index.scss new file mode 100644 index 000000000..93a5d3f35 --- /dev/null +++ b/public/react/src/modules/ecs/Home/index.scss @@ -0,0 +1,127 @@ +.ec-home { + .head-image { + width: 100%; + height: 240px; + background-size: 100% 100%; + justify-content: center; + align-items: center; + display: -webkit-flex; + } + + .ec-home-item { + background: #fff; + + &-head { + display: flex; + align-items: baseline; + margin-bottom: 20px; + } + + &-label { + margin-right: 20px; + font-size: 18px; + } + + &-tip { + color: #999; + font-size: 12px; + } + + &.major-list-item { + .ec-home-item { + &-head { + margin-bottom: -24px; + padding: 20px 30px; + justify-content: space-between; + align-items: center; + } + + &-tip { + font-size: 14px; + } + } + } + } + + .school-manager-item { + padding: 20px 30px; + } + + .ec-school-manager { + display: flex; + flex-wrap: wrap; + + &-item { + margin-right: 20px; + display: flex; + flex-direction: column; + align-items: center; + } + + &-name { + display: block; + text-align: center; + max-width: 48px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #666; + } + } + + .major-list-item { + .major-list { + &-container { + + } + + &-head { + margin-top: -24px; + padding: 20px 30px; + display: flex; + align-items: center; + justify-content: space-between; + + .total { font-size: 12px; } + } + + &-body { + padding-bottom: 30px; + } + + &-row { + padding: 10px 15px; + border-bottom: 1px solid #eee; + + &:last-child { border-bottom: unset; } + + &.head { + background: #F5F5F5; + } + .ant-btn-link { + text-align: center; + } + } + } + } + .operate-box { + .link { + margin: 0 5px; + } + } + .manager-box { + display: flex; + align-items: center; + + &-content { + flex: 1; + display: flex; + flex-wrap: wrap; + align-items: center; + } + } + + .link { + color: #007bff; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/ec.css b/public/react/src/modules/ecs/css/ec.css new file mode 100644 index 000000000..3c62678c9 --- /dev/null +++ b/public/react/src/modules/ecs/css/ec.css @@ -0,0 +1,27 @@ +.newedu-class-container{ + width:1240px; + height:84px; +} +.ecnewbutton{ + width:68px; + height:30px; + background:rgba(76,172,255,1); + border-radius:2px; + float:right; +} +.newedu-title-bottom{ + width:1240px; + height:65px; +} +.edu-con-bottom { + padding: 10px 0; + background: #fff; + font-size: 16px; +} + +.TabledataSource .ant-table-wrapper{ + width: 1240px; +} +.ant-table-thead{ + background:rgba(245,245,245,1); +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/ecCourseEvaluations.css b/public/react/src/modules/ecs/css/ecCourseEvaluations.css new file mode 100644 index 000000000..f27ad7313 --- /dev/null +++ b/public/react/src/modules/ecs/css/ecCourseEvaluations.css @@ -0,0 +1,576 @@ +.TrainingLecturer{ + font-size:18px; + font-family:MicrosoftYaHei; + font-weight:400; + color:#656565; +} +.TrainingTheory{ + font-size:18px; + font-family:MicrosoftYaHei; + font-weight:400; + color:#05101A !important; +} +#SystemParameters{ + height: 81px; + line-height: 40px; +} +#SystemParameters .SystemParameters:nth-child(1){ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + /* color:#989898 !important; */ +} +#SystemParameters .SystemParameters:nth-child(2){ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + color:#989898 !important; +} +.operationright{ + float:right !important; +} +.ml75{ + margin-left:75px; +} +.mlim30{ + margin-left:30px !important; +} +.RadioGroupbox{ + display: inline-block; + width: 100px; + height: 25px; + position: relative; +} +.RadioGroupboxab{ + position: absolute; + top: -5px; + left: 30px; +} +.buttoninline{ + display: inline-block; + margin-left: 29px; + position: relative; + /* width: 100px; */ + margin-top: 0px; + height: 25px; +} +.placeholder::-moz-placeholder{font-size:12px;} +.placeholder::-webkit-input-placeholder{font-size:12px;} +.placeholder:-ms-input-placeholder{font-size:12px;} +.mr16{ + margin-right:16px; +} +.defalutSubmitbtn{ + cursor: pointer; +} +.defalutCancelbtn{ + cursor: pointer; +} +.newSystem{ + background: #fff; +} +/* #EvaluationsList{ + padding:20px 0px; +} */ +.mt55{ + margin-top:55px !important; +} +.mb100{ + margin-bottom:100px !important; +} +.mt26{ + margin-top:26px !important; +} +.mb80{ + margin-bottom:80px !important; +} +.color99{ + color:#999999; +} +.ant-select-selection__placeholder{ + width: 100%; + font-size:14px; + height:58px; +} +.mt70{ + margin-top:70px; +} +.mb50{ + margin-bottom:50px; +} +/* 谷歌 */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; + font-size:14px; +} +/* 火狐 */ +input{ + -moz-appearance:textfield; + font-size:14px; +} +.ColorF68{ + color:#FF6800; +} +.eaSystemp a{ + color:#05101a; +} +.eaSystemp span{ + color: #05101a !important; +} +.editorModify div .ant-input-lg{ + font-size: 14px; +} +#Coursemultiple div div ul .ant-select-selection__choice{ + margin-left: 0px; + height: 20px !important; + min-height: 29px; + font-size: 14px; + line-height: 27px; + margin-top: 4px; + margin-bottom: 3px; +} + +#Coursemultiple .ant-select-selection--multiple{ + min-height: 40px !important; + line-height: 38px !important; +} +#Coursemultiple div div ul .ant-select-search.ant-select-search--inline{ + margin-left: 0px; + height: 20px !important; + min-height: 29px; + font-size: 14px; + line-height: 27px; + margin-top: 4px; + margin-bottom: 3px; +} +.neweditSubentry{ + position: relative; + top: -4px; + left: 7px; +} +.nulleditSubentry{ + position: relative; + top: -4px; + left: 3px; +} +.percentage{ + margin-left: 8px; + padding-left: 25px !important; +} +.Coursetitle{ + margin-bottom:0px !important; +} +.textaligncenter{ + padding-left: 30px !important; + width: 70px !important; +} +.ml72{ + margin-left:72px; +} + +.bordereaeaea{ + border-bottom: 1px solid transparent !important; +} +.ecnowrap{ + max-width: 170px; + display: inline-block; + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; + color: #40a9ff !important; + margin-right: 108px; +} +.ecblock{ + display: inline-block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.Spinlarge{ + text-align: center; + width: 100%; + margin-top: 25px; + margin-bottom: 25px; +} +/* .ant-select-search{ + display:none; +} +.ant-select-search--inline{ + display:none; +} */ +.boxinline-block{ + display: inline-block; +} +.boxinline{ + margin-right: 20px; +} +.evaluationdataClass{ + margin-left: 217px !important; + width: 589px !important; + display: inline-block; +} +.absolute{ + position:absolute; +} +.ml115{ + margin-left: 115px; +} +.ml100{ + margin-left: 100px; +} +.Importclassroomdata{ + position: absolute; + right: 18px; + top: 26px; +} +.Importclassroomdatas{ + position: absolute; + right: 375px!important; + top: 122px !important; +} +.Importclassroomdatass { + position: absolute; + right: 375px !important; + top: 248px !important; +} + +#SystemParameters{ + position: relative; +} + +.newSystem .newtarget_scoreclass{ + padding: 10px 0px !important; + margin: 0px 20px !important; +} + +.newSystem .newtarget_target{ + padding: 10px 0px !important; + margin: 0px 30px !important; + border-bottom:1px solid transparent !important; +} + +.nowrap329{ + max-width: 329px !important; + text-align: left; + overflow:hidden; + text-overflow:ellipsis; + white-space:nowrap; + color:transparent !important; + min-width: 329px !important; +} +.ListTableLine li>.column-500{ + max-width: 360px !important; + text-align: left; + min-width: 360px !important; +} +.color-666{ + color:#666666 !important; +} +.color-05101A{ + color:#05101A !important; +} +#SystemParametersP{ + position:relative; + margin-bottom:0px !important; +} +.major_name{ + cursor:inherit; +} +.padding1030{ + padding: 10px 30px; + height: 60px !important; +} +.color-red{ + color:#DD1717; +} +.color-redFF{ + color:#FF6666; +} +.margin-left63{ + margin-left: 63px !important; +} +.colorTransparent{ + color:transparent !important; +} +.color999{ + color: #999999 !important; +} +.operationrightbotton{ + margin-top: 2px!important; + margin-right: -25px; +} +.mr2{ + margin-right:2px; +} +.colorFF6800{ + color: #FF6800 !important; +} +.lineheight60{ + line-height: 52px !important; +} +.mr13{ + margin-right: 13px; +} +.mr14{ + margin-right: 14px; +} + +.ecmorelist{ + margin: 0 auto; + width: 100px; + /* height: 100px; */ + display: block; +} + +.padding10im{ + padding: 10px 0px !important; +} + +.lipadding10im{ + margin: 0 0px!important; +} + +.lipadding20im{ + padding: 10px 20px!important; +} + +.marlr19{ + margin: 0 19px!important; +} +.mrj15{ + margin-right: -15px; +} +.margin64px{ + margin: 0 64px!important; +} +.marginright84{ + margin-right: 84px!important; +} + +.marginright162{ + margin-right: 162px; +} +.width86{ + width: 86px!important; +} + +.ant-modal-mask { + background-color: rgba(5,16,26,0.4); +} +.ecmodeldelet{ + /* 考虑有各种尺寸的屏幕,用比例 */ + top:36%; +} +.ecmodeldelet .ant-modal-header{ + padding: 0px 24px; +} +.ecmodeldelet .ant-modal-title{ + padding: 0px 15px; + text-align: center; + box-sizing: border-box; + line-height: 70px; + height: 70px; + border-radius: 10px 10px 0px 0px; + font-size: 16px; + font-weight: bold; +} +a.TrainingLecturer:hover{ + color:#4CACFF !important; +} + +.newSystem .lipadding10im{ + margin: 0 0px!important; +} + +.operationleft{ + float:left !important; +} +.color4D4D4D{ + color:#4D4D4D !important; +} + +/* #SystemParameters .SystemParameters:nth-child(1){ + color:#4D4D4D !important; +} */ + +.color4CACFF{ + color:#4CACFF !important; +} + +.SystemParameters4CACFF{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + line-height: 45px; +} + +.detaillist{ + text-align: center !important; + width: 133px !important; + height: 24px ; +} + +.associatedclass{ + margin-right: 128px !important; +} + +.associatedclasslist{ + width: 234px; + height: 20px; + font-size: 14px; + font-family: MicrosoftYaHei; + font-weight: 400; + color: rgba(101,101,101,1); + line-height: 22px; + margin: 6px auto; +} + +.associatedclasslists{ + width: 323px; + height: 35px; + font-size: 14px; + font-family: MicrosoftYaHei; + font-weight: 400; + color: rgba(101,101,101,1); + line-height: 22px; + margin: 6px auto; + margin-bottom: 15px; +} +.newecmodeldelet{ + width:600px !important; + top:100px; +} + +.assclasslistsearch{ + width:454px; + height:36px; + background:rgba(244,244,244,1); + border:1px solid rgba(234,234,234,1); + border-radius:4px; + position: relative; +} + +.assclassposition{ + position: absolute; + top: 3px; + left: 9px; +} + +.assclasslistsearchbtn{ + width: 64px; + height: 35px !important; + font-weight: 300 !important; + line-height: 35px !important; +} +.btnweight{ + font-weight: 300 !important; + color: #fff !important; +} + +.CBCBCB{ + background:#CBCBCB!important; +} +.clear{ + clear: both; +} +.ml120{ + margin-left: 120px; +} +.ml88{ + margin-left: 88px; +} +.assclasslistmid{ + width: 540px; + height: 282px; + background: rgba(244,250,255,1); + border-radius: 4px; + margin-left: 10px; + overflow: auto; + padding-top: 10px; +} + +.assclasslistsubmit{ + margin-top: 26px !important; + margin-bottom: 8px !important; +} +.ant-modal-header{ + border-top-left-radius:10px; + border-top-right-radius:10px; +} +.ant-modal-content{ + border-radius: 10px; +} +.assclasslistmidname{ + width: 160px; + overflow: hidden; + /* height: 24px; */ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.bordereaeaeas{ + border-bottom: 1px solid #eaeaea !important; +} +.isreloadsbtn{ + width: 80px !important; + font-weight: 400 !important; + padding: 0px !important; + padding-left: 10px !important; +} + +.f5f5f5{ + color:rgb(245, 245, 245) !important; +} + +.ant-select-selection{ + border-radius: 0px !important; + background-color: #F5F5F5; +} + +.ant-select-selection:focus{ + border-radius: 0px !important; + background-color: #fff; + border-color: #d9d9d9 !important; +} + +.listchildbox{ + overflow: hidden; +} + +.listchildboxs{ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ant-input:focus, .ant-input:hover{ + border-color: transparent; +} +.inputWeight{ + background-color: #F5F5F5; +} +.inputWeight:focus { + background-color: #fff; + } + .ant-input:focus { + outline: 0; + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + + .ant-input{ + border-color: #d9d9d9 !important; + } + +.mt60{ + margin-top:60px; +} + +.SystemParameters{ + height:auto; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/ecCourseSupports.css b/public/react/src/modules/ecs/css/ecCourseSupports.css new file mode 100644 index 000000000..10b6ebd91 --- /dev/null +++ b/public/react/src/modules/ecs/css/ecCourseSupports.css @@ -0,0 +1,368 @@ +.eaSystemp a{ + color:#05101a; +} +.eaSystemp span{ + color: #05101a !important; +} +.eacourse p{ + height:84px; + margin-bottom:0px !important; +} +.eacourse #training_objective_contents{ + height:81px; +} +.courseSystem{ +font-size:18px; +font-family:MicrosoftYaHei; +font-weight:400; +line-height:45px; +color:rgba(5,16,26,1); +} +.SystemParameters{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + line-height:45px; + color:rgba(50,50,50,1); +} +.SystemParametersysls{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + color:rgba(50,50,50,1); +} +.Systemnum{ + font-size:14px; + font-family:MicrosoftYaHei; + font-weight:400; + color:#FF6800; +} +.newSystem{ + width:1200px; + overflow:auto; + background: #FFF; +} +.newSystem .clearfix .column-1{ + width: 113px !important; + text-align: center; +} +.operationColumn{ + margin: 0px 10%; + width:100%; + height:100%; +} +.operationalter{ + margin: 20px 16px; +} +.SystemModifythelist .column-1{ + width: 120px !important; + text-align: center; +} + +.SystemModifythelist .column-3{ + padding-left: 96px; + margin-right: 23px; +} +.operationright{ + float:right !important; +} + +.newSystem p{ + /*padding: 10px 33px !important;*/ + margin-bottom: 0em; +} +.newSystem li{ + margin:0 !important; +} +.SystemModifythelist{ + background:#FFF !important; +} + +.SystemModifythelist .column-1:nth-child(1){ + margin-left: 7px; +} + +.Systempoint{ + font-size:12px; + font-family:MicrosoftYaHei; + font-weight:400; + color:rgba(152,152,152,1); +} +.editorModify{ + background:#FFF !important; +} +.newSystem .editorModify .column-1{ + width: 194px !important; + text-align: left; + margin-left: 30px; +} +.newSystem .editorModify .column-1:nth-child(1){ + margin-right: 510px; +} +.editorModify .ant-select{ + width: 556px !important; + margin-left: 36px; +} +.editorModify .ant-select .ant-select-selection{ + height: 30px !important; +} +.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered{ + height: 30px !important; +} +.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered .ant-select-selection-selected-value{ + line-height: 30px !important; +} +.inputWeight{ + width: 20%; + font-size:14px; + height:30px; + margin-left: 20px; + background-color: #F5F5F5; +} +.SetTheAssociated{ + width: 314px; + height: 30px; + float: right; + margin-right: -3.5%; +} +.SetTheAssociatedchild{ + width: 120px; + height: 30px; + background: rgba(255,255,255,1); + border: 1px solid rgba(234,234,234,1); + border-radius: 4px; + float: left; + margin-right: 10px; + text-align: center; + line-height: 30px; + /*margin-left: 34px;*/ +} +.operatebutton{ + margin-left: 20px; + /* margin-top: 16px; */ +} +.editbulebutton{ + width:120px; + height:30px; + background:rgba(76,172,255,1); + border-radius:2px; + color:#FFF; + text-align: center; + line-height: 30px; +} +.editglybutton{ + width:120px; + height:30px; + border:1px solid rgba(205,205,205,1); + border-radius:2px; + color:#999; + text-align: center; + line-height: 30px; +} + +.editglybuttonbox{ + width: 275px; + margin-bottom: 30px; + margin-right: 20px; + margin-right:7%; +} +.editglybuttonboxs{ + width: 275px; + margin-bottom: 30px; + margin-right: 20px; + margin-right:3%; +} +.defalutCancelbtn:hover { + border: 1px solid #B2B2B2; + color: #B2B2B2!important; +} + +.gouxuanbule{ + color:#4CACFF; +} +.gouxuanwhite{ + color:#FFF; +} +.icon-gouxuan{ + cursor: pointer; +} +/* 谷歌 */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + appearance: none; + margin: 0; +} +/* 火狐 */ +input{ + -moz-appearance:textfield; +} +.inputWeight{ + text-indent:0.625rem; +} + +.columnlocation{ + height: 40px; + line-height: 40px; +} +.paddingLF{ + padding:0 33px; +} +.width20{ + width: 20px; + height: 20px; + text-align: center; +} +.defalutSubmitbtn,.defalutCancelbtn{ + cursor: pointer; +} +.mb290{ + margin-bottom:290px; +} +.Spinlarge{ + text-align: center; + width: 100%; + margin-top: 25px; + margin-bottom: 25px; +} +.DDred{ + color:#DD1717; +} +.color-666{ + color:#666666 !important; +} +.color-05101A{ + color:#05101A !important; +} +.ec_graduation_name{ + margin-right:20px !important; +} +.column-width575{ + color: transparent !important; +} +.column-width130{ + width: 130px !important; + height: 40px; +} + + +.ListTableLine li>span { + max-width: 550px !important; +} + +.graduateRequirement .clearfix .column-1 { + width: 76px!important; +} +.newrightcalculatebutton{ + width: 50px; + height: 25px; + border: 1px solid rgba(76,172,255,1); + border-radius: 1px; + line-height: 25px; + text-align: center; + margin-top: 7px; + cursor: pointer; + color: rgba(76,172,255,1); +} +.newrightcalculatebuttons{ + width: 50px; + height: 25px; + border: 1px solid rgba(76,172,255,1); + border-radius: 1px; + line-height: 25px; + text-align: center; + margin-top:9px; + cursor: pointer; + color: rgba(76,172,255,1); + } +.columnbox{ + height: 53px; + overflow: hidden; +} + +.ant-modal-mask { + background-color: rgba(5,16,26,0.4); +} +.ecmodeldelet{ + top:300px; +} +.ecmodeldelet .ant-modal-header{ + padding: 0px 24px; +} +.ecmodeldelet .ant-modal-title{ + padding: 0px 15px; + text-align: center; + box-sizing: border-box; + line-height: 70px; + height: 70px; + border-radius: 10px 10px 0px 0px; + font-size: 16px; + font-weight: bold; +} +.bor-red { + border: 1px solid #db0505 !important; +} + +.ml93{ + margin-left:93px; +} +.ml26{ + margin-left: 26px; +} +.finishtarget{ + width: 69px; + /* height: 48px; */ + line-height: 20px; + text-align: center; + margin-right: 48px; +} + +.bordereaeaea{ + border-bottom: 1px solid transparent !important; +} + +.heightimportant{ + height: 30px !important; + background-color: #F5F5F5; +} +.heightimportant:focus { + background-color: #fff; +} +.inputWeight:focus { + background-color: #fff; + } +.heightlineimportant{ + line-height: 30px !important; +} + +.ant-select-selection:hover{ + border-color: #d9d9d9 !important; +} +.ant-input:focus { + outline: 0; + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + .ant-input{ + border-color: #d9d9d9 !important; + } + .ant-select-selection:focus{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + .ant-select-selection:active{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + + .ant-select-selection:focus{ + border-color: #d9d9d9 !important; + } + .ant-select-selection{ + -webkit-box-shadow: 0 0 0 2px transparent !important; + box-shadow: 0 0 0 2px transparent !important; + } + +.mt60{ + margin-top:60px; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/search.svg b/public/react/src/modules/ecs/css/search.svg new file mode 100644 index 000000000..cf0e16c0c --- /dev/null +++ b/public/react/src/modules/ecs/css/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js new file mode 100644 index 000000000..3dae260de --- /dev/null +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -0,0 +1,255 @@ +import React, { Component } from 'react'; +import classNames from 'classnames' + +import axios from 'axios'; + +import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { message,Modal,Spin,Icon} from 'antd'; + +import 'antd/dist/antd.css'; + +import EcTitleCourseEvaluations from '../ecTitle/ecTitle' + +import '../css/ecCourseSupports.css'; + +import '../css/ecCourseEvaluations.css'; +import { + BrowserRouter as Router, + Route, + Switch +} from 'react-router-dom'; +import Loadable from 'react-loadable'; +import Loading from "../../../Loading"; +const $ = window.$; +const Curriculumtwo = Loadable({ + loader: () => import('./Curriculumtwo'), + loading: Loading, +}) +const EcCourseEvaluationsbottom =Loadable({ + loader: () => import('../subroute/ecCourseEvaluations/EcCourseEvaluationsbottom'), + loading: Loading, +}); +const EcCompletionCalculation =Loadable({ + loader: () => import('../subroute/ecCompletion_calculation/EcCompletionCalculation'), + loading: Loading, +}); + + +class Curriculum extends Component { + //课程体系 + constructor(props) { + super(props) + this.state= { + classcalue:5, + newec_course_idbottom:"", + course_name:undefined, + course_url:"a", + ecmanager:true, + titine:1, + } + } + + componentWillMount(){ + // window.document.title = '课程达成评价结果'; + } + componentDidMount(){ + console.log(this.props); + } + sync_course_data=()=>{ + // this.setState({listSpin:true}) + // let ec_course_id=this.props.match.params.ec_course_id; + // let Url ='/ec_course_achievement_methods/sync_course_data'; + // axios.post(Url, { + // ec_course_id:ec_course_id + // }, + // { + // withCredentials: true + // } + // ).then((response) => { + // if(response.data.status===0){ + // this.setState({ + // // titlemessage: response.data.message+"(支撑关系变更)", + // Modallist: response.data.message, + // Modallisttype:true, + // listSpin:false + // }) + // this.UpdateEvaluations(); + // }else if(response.data.status===-1){ + // this.setState({ + // // titlemessage: response.data.message+"(支撑关系变更)", + // Modallist: response.data.message, + // Modallisttype:true, + // listSpin:false + // }) + // + // } + // }).catch((error) => { + // console.log(error) + // }) + + } + + onAclick=(i)=>{ + console.log("onAclick"); + console.log(i); + if(i===1){ + this.props.history.push(this.props.match.url+"/ec_course_support_setting/1"); + }else if(i===2){ + this.props.history.push(this.props.match.url+"/ec_course_reach_setting/2"); + }else if(i===3){ + this.props.history.push(this.props.match.url+"/score_level/3"); + }else if(i===4){ + this.props.history.push(this.props.match.url+"/evaluation_methods/4"); + }else{ + this.props.history.push(this.props.match.url+"/competition_calculation_info/5"); + } + this.setState({ + titine:i, + }) + + }; + Ontitine=(s)=>{ + if(s==="ec_course_support_setting"){ + this.setState({ + titine:1, + }) + }else if(s==="ec_course_reach_setting"){ + this.setState({ + titine:2, + }) + }else if(s==="score_level"){ + this.setState({ + titine:3, + }) + }else if(s==="evaluation_methods"){ + this.setState({ + titine:4, + }) + }else if(s==="competition_calculation_info"){ + this.setState({ + titine:5, + }) + } + + }; + associatedclass=()=>{ + + }; + deleteassociatedclass=()=>{ + + } + render() { + let {newec_course_idbottom,titine,classcalue,course_name,course_url,ecmanager,Spintype,calculatesetype,ec_course_id,course_total_scoreaverage,ec_course_targets_count,schooldata,ecComponentState,course_total_score,total_rate_data,ec_course_targets,graduation_list,target_list,target_score,evaluate_result,morelisttype,titlemessage,completiontype,completionlist,ismanager} = this.state; + // console.log("Curriculum"); + // console.log(this.props); + // console.log(titine); + return ( +
                  +
                  +
                  + +
                  + 课程体系 > + {schooldata&&schooldata.ec_course_name} 达成评价详情 + {/* 导出培养目标 */} +
                  系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
                  + { + titine === 4 ? + + 导出评价方法 + + :titine === 1 ? + + 导出课程目标 + + :titine===2? + + :"" + } +
                  + +
                  + this.onAclick(1)}>1.课程目标 + this.onAclick(2)}>2.课程考核方式与数据来源 + this.onAclick(3)}>3.成绩等级设置 + this.onAclick(4)} + >4.课程目标评价方法 + this.onAclick(5)} + >5.课程达成评价结果 + { + titine===5? + + + 导出评价详情 + + 计算 + + :titine===4? + (各环节平均得分*占比)之和/(各环节总分*占比)之和 + :titine===3? + (将学生的成绩转换成对应的等级) + :titine===2? + + (请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统) + 导入课堂数据 + + :"" + } +
                  +
                  + + {/*Curriculumtwo 测试用*/} + {/*课程目标*/} + (this.Ontitine(i)} />) }> + {/*课程考核方式与数据来源*/} + (this.Ontitine(i)}/>) }> + {/*成绩等级设置*/} + (this.Ontitine(i)}/>) }> + {/*4课程目标评价方法*/} + (this.Ontitine(i)}/>) }> + {/*5课程达成评价结果*/} + (this.Ontitine(i)}/>) }> + +
                  +
                  + ) + } + + +} +export default Curriculum; \ No newline at end of file diff --git a/public/react/src/modules/ecs/curriculum/Curriculumtwo.js b/public/react/src/modules/ecs/curriculum/Curriculumtwo.js new file mode 100644 index 000000000..221b2afb5 --- /dev/null +++ b/public/react/src/modules/ecs/curriculum/Curriculumtwo.js @@ -0,0 +1,32 @@ +import React, { Component } from 'react'; + +class Curriculumtwo extends Component { + //测试用 + constructor(props) { + super(props) + // console.log(props); + } + + componentWillMount(){ + } + componentDidMount(){ + // console.log(this.props); + console.log("Curriculumtwo"); + console.log(this.props.match.params.type); + this.props.Ontitine(this.props.match.params.type); + } + + + render() { + // console.log("Curriculumtwo"); + // console.log(this.props); + return ( +
                  + 测试 +
                  + ) + } + + +} +export default Curriculumtwo; \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/ecTitle.css b/public/react/src/modules/ecs/ecTitle/ecTitle.css new file mode 100644 index 000000000..3f6796cdd --- /dev/null +++ b/public/react/src/modules/ecs/ecTitle/ecTitle.css @@ -0,0 +1,104 @@ +#traningNav { + display: flex +} + #traningNav>li { + float: none !important; +} + /* 最后一个item 占满剩余空间 */ +#traningNav>li:last-child{ + flex: 1; +} + +#traningNav>li>.ecTitle { + width: 24px; + height: 24px; + border: 1px solid rgba(65, 140, 205, 1); + border-radius: 50%; + text-align: center; + line-height: 22px; + display: inline-block; + color: rgba(65, 140, 205, 1) !important; + margin-right: 10px; +} +#traningNav>li>.ecTitles { + line-height: 16px !important; + height: 18px!important; + width: 18px!important; +} + +#traningNav>li>.ecTitlefont:hover{ + color: rgba(65, 140, 205, 1) !important; +} + +.ecimgs3{ + background: url("./img/3.png"); + background-repeat: no-repeat; + background-size: 100% 100%; + -moz-background-size: 100% 100%; + height: 90px; + line-height: 90px; + width: 235px; +} +.ecimgs2{ + background: url("./img/4.png"); + background-repeat: no-repeat; + background-size: 100% 100%; + -moz-background-size: 100% 100%; + height: 90px; + line-height: 90px; + width: 190px; +} +.ecimgs11{ + background: url("./img/3.png"); + background-repeat: no-repeat; + background-size: 100% 100%; + -moz-background-size: 100% 100%; + height: 90px; + line-height: 90px; + width: 146px; +} +.ml18{ + margin-left: 18px; +} +.ecimgs{ + height: 90px; + line-height: 90px; +} +.ecmarginleft{ + margin-left: 23px; +} + +#traningNav>li>.ecTitlefontFFF{ + color:#fff !important; +} + +#traningNav>li>.ecTitleFFF { + width: 24px; + height: 24px; + border: 1px solid #fff; + border-radius: 50%; + text-align: center; + line-height: 22px; + display: inline-block; + color: #fff !important; + margin-right: 10px; +} +.traningNavs{ + padding: 0px 0px 0px 0px !important; +} +.traningNavs>li{ + padding: 0px 10px 30px 10px !important; +} + +.mb0{ + margin-bottom: 0px !important; +} + +.info2{ + width:232px; + text-align: center; +} +.info1{ + width: 206px; + text-align: center; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/ecTitle.js b/public/react/src/modules/ecs/ecTitle/ecTitle.js new file mode 100644 index 000000000..f24409018 --- /dev/null +++ b/public/react/src/modules/ecs/ecTitle/ecTitle.js @@ -0,0 +1,100 @@ +import React, { Component } from 'react'; +import './ecTitle.css'; + +class EcTitleCourseEvaluations extends Component { + constructor(props) { + super(props) + this.state = { + schooldata:{}, + ecComponentState:"", + ecpaths:"" + } + } + componentWillReceiveProps(nextProps){ + const {schooldata,ecComponentState,ecpath}=nextProps; + this.setState({ + schooldata:schooldata, + ecComponentState:ecComponentState, + ecpaths:ecpath + }) + } + + render() { + let{schooldata,ecComponentState,ecpaths}=this.state; + + return ( +
                  + + + +
                  + )} +} + +export default EcTitleCourseEvaluations; \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/img/1.png b/public/react/src/modules/ecs/ecTitle/img/1.png new file mode 100644 index 000000000..28325a3ea Binary files /dev/null and b/public/react/src/modules/ecs/ecTitle/img/1.png differ diff --git a/public/react/src/modules/ecs/ecTitle/img/2.png b/public/react/src/modules/ecs/ecTitle/img/2.png new file mode 100644 index 000000000..4a558df21 Binary files /dev/null and b/public/react/src/modules/ecs/ecTitle/img/2.png differ diff --git a/public/react/src/modules/ecs/ecTitle/img/3.png b/public/react/src/modules/ecs/ecTitle/img/3.png new file mode 100644 index 000000000..da3d47779 Binary files /dev/null and b/public/react/src/modules/ecs/ecTitle/img/3.png differ diff --git a/public/react/src/modules/ecs/ecTitle/img/4.png b/public/react/src/modules/ecs/ecTitle/img/4.png new file mode 100644 index 000000000..37dab8ea0 Binary files /dev/null and b/public/react/src/modules/ecs/ecTitle/img/4.png differ diff --git a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js new file mode 100644 index 000000000..4be7c11d3 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js @@ -0,0 +1,809 @@ +import React, { Component } from 'react'; +import classNames from 'classnames' + +import axios from 'axios'; + +// import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { message,Modal,Spin,Icon} from 'antd'; + +import 'antd/dist/antd.css'; + +import EcTitleCourseEvaluations from '../../ecTitle/ecTitle' + +import '../../css/ecCourseSupports.css'; + +import '../../css/ecCourseEvaluations.css'; + +const $ = window.$; +class EcCompletionCalculation extends Component { + constructor(props) { + super(props) + this.state={ + schooldata:{}, + ecComponentState:"ecCompletion", + course_total_score:[], + ec_course_targets:0, + graduation_list:[], + target_list:[], + target_score:[], + evaluate_result:"", + ec_course_targets_count:0, + new_target_ec_year_id:0, + total_rate_data:undefined, + calculatetype:false, + ec_course_id:0, + morelisttype:false, + titlemessage:"提示", + completiontype:false, + completionlist:"", + course_total_scoreaverage:0, + calculatesetype:false, + Spintype:false, + ismanager:false + } + } + + componentWillMount(){ + window.document.title = '课程达成评价结果'; + } + + componentDidMount(){ + let ec_course_id =this.props.match.params.ec_course_id; + this.UpdateClassData(true); + const Url =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id; + axios.get(Url, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data, + ec_course_id:ec_course_id + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + targetsget_navigation_data=(ec_year_id,ec_course_id)=>{ + const Url =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id; + axios.get(Url, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data, + ec_course_id:ec_course_id + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + showmorelist=()=>{ + this.setState({ + morelisttype:false + }) + this.UpdateClassData(false) + } + UpdateClassData=(key)=>{ + let {calculatetype} =this.state; + let ec_course_id =this.props.match.params.ec_course_id; + this.setState({ + ec_course_id:ec_course_id + }) + const Arl =`/ec_courses/`+ec_course_id+`/calculation_info_data`; + axios.get(Arl, { + withCredentials: true, + }) + .then((response) => { + + if(response.status===200){ + // var list=[]; + // if(key===true){ + // for(var i=0; i10){ + newmorelisttype=true + + } + + let course_total_scoreaverage; + let newlist=response.data.course_total_score[response.data.course_total_score.length-1].total_rate; + for(var i=0; i{ + this.setState({ + Spintype:true + }) + let {ec_course_id}=this.state; + const Orl =`/ec_courses/`+ec_course_id+`/sync_data`; + axios.get(Orl, { + withCredentials:true, + }) + .then((response) => { + if(response.data.status===1){ + this.setState({ + calculatetype:true, + completiontype:true, + completionlist:'计算成功', + calculatesetype:true, + Spintype:false + }) + this.UpdateClassData(true); + } + }) + .catch(function (error) { + console.log(error) + }); + } + hidecompletion=()=>{ + this.setState({ + completiontype:false, + completionlist:"", + calculatesetype:false + }) + } + render() { + let {Spintype,calculatesetype,ec_course_id,course_total_scoreaverage,ec_course_targets_count,schooldata,ecComponentState,course_total_score,total_rate_data,ec_course_targets,graduation_list,target_list,target_score,evaluate_result,morelisttype,titlemessage,completiontype,completionlist,ismanager} = this.state; + + let TargetresList = (length) => { + let target_listres = []; + for(let i = 0; i < length; i++) { + // target_listres.push(目标{length-i}) + // target_listres.push(目标{i+1}) + target_listres.push(目标{length-i}) + } + return target_listres + } + + let TargetresLists = (length) => { + let target_listress = []; + for(let i = 0; i < length; i++) { + // target_listres.push(目标{length-i}) + target_listress.push(目标{i+1}) + // target_listres.push(目标{length-i}) + } + return target_listress + } + + let TargetresContentList = (length,value) => { + let target_listres = []; + if(value!=undefined){ + for(let i = 0; i < length; i++) { + + if(value[i]===1){ + target_listres.push() + }else{ + target_listres.push() + } + + } + target_listres.reverse() + return target_listres + } + } + + + + let Total_rate_dataList = (value) => { + + let target_listres = []; + if(value!=undefined){ + for(let i = 0; i < value.length; i++) { + + if(i===value.length-1){ + target_listres.push( + {/*
                  {value[i].total_score}
                  */} +
                  100%
                  +
                  ) + }else{ + target_listres.push( + {/*
                  {value[i].score}
                  */} + {/*
                  占比{(value[i].rate*100).toFixed(2)}%
                  */} +
                  + {(value[i].rate*100).toFixed(2)}% +
                  +
                  ) + } + + } + return target_listres + }else{ + target_listres.push( + {/*
                  {value[i].total_score}
                  */} +
                  --
                  +
                  ) + return target_listres + } + } + + let newTotal_rate_dataList = (length,value) => { + + let target_listres = []; + if(value!=undefined){ + for(let i = 0; i < value.length; i++) { + + // if(i===0){ + // target_listres.push( + //
                  {value[i].score.toFixed(2)}
                  + //
                  ) + // }else{ + // target_listres.push( + //
                  {value[i].score.toFixed(2)}
                  + //
                  ) + // } + + if(i +
                  {value[i].score.toFixed(2)}
                  + ) + } + + } + return target_listres + } + } + return ( +
                  + +
                  +
                  {completionlist}
                  +
                  + { + calculatesetype===true? +
                  + 知道啦 +
                  + : +
                  + 取消 + 确定 +
                  + } + + + +
                  + +
                  + + {/**/} + + {/*
                  */} + {/*
                  */} + {/* 课程体系 >*/} + {/* {schooldata.ec_course_name} 达成评价详情*/} + {/* /!* 导出培养目标 *!/*/} + {/*
                  系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
                  */} + {/*
                  */} + {/*
                  */} + {/* 1.课程目标*/} + {/* 2.课程考核方式与数据来源*/} + {/* 3.成绩等级设置*/} + {/* 4.课程目标评价方法*/} + {/* 5.课程达成评价结果*/} + {/* /!* 课程体系:*/} + {/* {*/} + {/* evaluate_result===false?未达成:达成*/} + {/* }*/} + {/* *!/*/} + {/* 计算*/} + {/* */} + {/* 导出评价详情*/} + {/* */} + {/*
                  */} + {/*
                  */} + +
                  + +

                  + 课程目标 + 达成结果 + 达成标准(分) + 实际达成 + 权重 +

                  + + { Spintype===true?}/>:"" } + + { target_list.length===0&&Spintype===false? +
                • + -- + -- + -- + -- + -- + -- +
                • :""} + + + {Spintype===false?target_list.map((item,key)=>{ + + return( +
                • + {key+1} + {item.content} + {item.result} + {item.standard_grade} + {item.real_grade} + {item.weigths} +
                • + ) + + }):"" + } + + +
                  + +
                  + +
                  + 毕业要求指标点达成评价结果 + 注: 代表支持指标点;代表不支持指标点 +
                  + +
                  + +
                  + + { + graduation_list.length===0? +

                  + 毕业要求 + {5} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(5)} +

                  + :"" + } + + { Spintype===true?}/>:"" } + + { + graduation_list.length===0&&Spintype===false? +
                • + {/* {item.ec_graduation_name} */} + {1} + {"--"} + {"--"} + {"--"} + {"--"} + 立即配置 + {TargetresContentList(5,[2,2,2,2,2])} +
                • + :"" + } + { + Spintype===false?graduation_list.map((item,key)=>{ + + if(key===0){ + return( +

                  5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> + 毕业要求 + {item.ec_subitem_content} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(ec_course_targets_count)} +

                  + ) + } + + }):"" + } + + + { + Spintype===false?graduation_list.map((item,key)=>{ + + return( +
                • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> + {/* {item.ec_graduation_name} */} + {key+1} + {item.ec_subitem_content} + {item.result} + {item.reach_target===null?0:item.reach_target} + {item.reach_real_target===null?0:item.reach_real_target} + {item.weight===null||item.weight===0?立即配置:{item.weight}} + {TargetresContentList(ec_course_targets_count,item.target_position)} +
                • + ) + + }):"" + } +
                  + +
                  + +
                  + 课程总评成绩表 +
                  + +
                  + +
                  + +

                  5 ? (180 * total_rate_data+226+16) : 1200+"px"}}> + {/*序号*/} + 课程目标 + {/*姓名*/} + {/*学号*/} + {TargetresLists(total_rate_data-1)} + 总评成绩 +

                  + {/*style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4.5):1136+"px"}}*/} + { + // course_total_score.map((i,k)=>{ + + // if(k===course_total_score.length-1){ + + // return( + //
                • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // 占比 + // {/*colorTransparent*/} + // {/* 平均数 */} + // {/* 平均数 */} + // {/* {Total_rate_dataList(total_rate_data-1,i.total_rate)} + //
                • + // ) + + // } + + // }) */} + } + { Spintype===true?}/>:"" } + { + Spintype===false?
                • 5 ? (180 * total_rate_data+226+16) : 1200 + "px"}}> + 占比 + {/*colorTransparent*/} + {/* 平均数 */} + {/* 平均数 */} + {Total_rate_dataList(course_total_score)} + { + course_total_score.length===0? --:"" + } +
                • :"" + } + {/*style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4):1136+"px"}}*/} + { + // course_total_score.map((i,k)=>{ + + // if(k!=course_total_score.length-1){ + + // return( + //
                • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // {/*{k+1}*/} + // 平均分 + // {/*{i.student_scores.name}*/} + // {/*{i.student_scores.student_number}*/} + // {newTotal_rate_dataList(total_rate_data-1,i.student_scores.target_info)} + // {i.student_scores.total_score.toFixed(2)} + //
                • + // ) + + // } + + // }) + } + { + Spintype===false?
                • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + {/*{k+1}*/} + 平均分 + {/*{i.student_scores.name}*/} + {/*{i.student_scores.student_number}*/} + {newTotal_rate_dataList(course_total_score-1,course_total_score)} + {/* {course_total_score.length===0?"":course_total_score[course_total_score-1].total_score} */} + { + course_total_score.length===0? --:{course_total_scoreaverage} + } +
                • :"" + } + + +
                • 1136?113*(total_rate_data+4):1136+"px",display:morelisttype===true?"block":"none"}}> + this.showmorelist()}>加载更多 +
                • +
                  + + + +
                  + +
                  + 课程目标成绩分析 +
                  + +
                  + + +
                  + +

                  + 课程目标 + 平均分 + 最高分数 + 最低分数 + 90分以上 + 80-89分 + 70-79分 + 60-69分 + 50-59分 + 低于50分 +

                  + + { + Spintype===false?target_score.map((i,k)=>{ + + return( +
                • + {k+1} + {i.average_score} + {i.top_score} + {i.low_score} + +
                  {i.from90[0]}人
                  +
                  {(i.from90[1]).toFixed(2)}%
                  +
                  + +
                  {i.from80[0]}人
                  +
                  {(i.from80[1]).toFixed(2)}%
                  +
                  + +
                  {i.from70[0]}人
                  +
                  {(i.from70[1]).toFixed(2)}%
                  +
                  + +
                  {i.from60[0]}人
                  +
                  {(i.from60[1]).toFixed(2)}%
                  +
                  + +
                  {i.from50[0]}人
                  +
                  {(i.from50[1]).toFixed(2)}%
                  +
                  + +
                  {i.from_down[0]}人
                  +
                  {(i.from_down[1]).toFixed(2)}%
                  +
                  +
                • + ) + + }):"" + } + + { Spintype===true?}/>:"" } + + {target_score.length===0&&Spintype===false? +
                • + -- + -- + -- + -- + +
                  --人
                  +
                  --%
                  +
                  + +
                  --人
                  +
                  --%
                  +
                  + +
                  --人
                  +
                  --%
                  +
                  + +
                  --人
                  +
                  --%
                  +
                  + +
                  --人
                  +
                  --%
                  +
                  + +
                  --人
                  +
                  --%
                  +
                  +
                • :""} + +
                  + +
                  +
                  + ); + } +} + +export default SnackbarHOC() (EcCompletionCalculation); + diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js new file mode 100644 index 000000000..6e27711b2 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -0,0 +1,1039 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import classNames from 'classnames' + +import axios from 'axios'; + +// import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Select,InputNumber,message,Modal,Input,Radio,Spin,Icon,Tooltip } from 'antd'; + +import 'antd/dist/antd.css'; + +import '../../css/ecCourseEvaluations.css'; +import EcTitleCourseEvaluations from "../../ecTitle/ecTitle"; + +const $ = window.$; + +// 课程目标评价方法 +class EcCourseEvaluationsbottom extends Component { + constructor(props) { + super(props) + this.state={ + totalevaluations_list:[], + ec_course_target_id:0, + achievement_list:[], + evaluations_listSelec:[], + evaluations_lists: [], + evaluation_subitems_lists: [], + evaluations_list:[], + evaluation_subitems_list:{}, + achievement_methods:[], + ec_course_target_name:"", + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + spinningstate:true, + schooldata:{}, + sequenceid:0, + target_id:null, + titlemessages:"提示", + Modallists:"", + eacoursetype:false, + eacoursesavetypes:false, + newec_course_idbottom:undefined, + methodologytype:false, + meweacoursetype:false, + newshowredvalue:false, + percentagetype:false, + ismanager:false + } + } + getec_course_achievement_methods=()=>{ + const {newec_course_idbottom}=this.state; + if(newec_course_idbottom!=undefined){ + const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + } + // this.setState({ + // achievement_list:[ + // {target_evaluate_data: [ + // { + // evaluate_id: 24, + // evaluate_name: "期末考试", + // evaluation_relates_data: [ + // {evaluation_relates_id: 31, evaluation_relates_name: "期末考试1目标1考题"}, + // {evaluation_relates_id: 32, evaluation_relates_name: "期末考试1目标2考题"} + // ], + // percentage: 100, + // score: 15 + // } + // ], + // target_id: 5 + // }, + // ], + // spinningstate:false + // }) + + + } + + getNavigationData=(ec_course_id)=>{ + // const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id; + const jol =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id; + axios.get(jol, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + + }) + .catch(function (error) { + console.log(error); + }); + } + componentDidMount(){ + let ec_course_id=this.props.match.params.ec_course_id; + const url = `/ec_course_achievement_methods?ec_course_id=`+ec_course_id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + + this.getNavigationData(ec_course_id); + this.setState({ + newec_course_idbottom:ec_course_id + }) + } + editecCourseEvaluationslist=(e)=>{ + let id =e.target.getAttribute("target_id"); + let newid =e.target.name; + + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + target_id:id, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").show(); + // $("#SystemParametersbottom").show(); + // let offsettop=$("#ecCourseEvaluationsbottomsubmit").position().top||$("#ecCourseEvaluationsbottomsubmit").scrollTop || $("#ecCourseEvaluationsbottomsubmit").pageYOffset; + // window.scrollTo(0, offsettop) + + let {evaluations_list,evaluation_subitems_list,achievement_methods} = this.state; + this.setState({ + achievement_methods:undefined, + selectevaluation_phase:[], + course_select_value:'', + evaluations_lists:[], + sequenceid:newid, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false + }) + + let newevaluations_list=[]; + let newevaluation_subitems_list=new Object (); + let newachievement_methods=[]; + const url = `/ec_course_achievement_methods/edit_course_target?ec_course_target_id=`+id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + if(response.status===200){ + if(response.data.evaluation_phase_list.length===0){ + this.setState({ + achievement_methods:undefined + }) + let newObject=new Object (); + newachievement_methods.push(newObject) + } + + if(response.data.evaluation_phase_list.length>0){ + let evaluation_phase_list=response.data.evaluation_phase_list; + let evaluations_list=response.data.evaluations_list; + for(var i=0; i{ + + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=keythis.key; + let list=totalevaluations_list.evaluations_list; + // 点击切换清空 + for(var z=0; z0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + let{totalevaluations_list,achievement_methods}=this.state; + let newachievement_methods=[]; + let id; + if(value.length>0){ + + newachievement_methods=achievement_methods + for(var j=0; j{ + let id=parseInt(keynum.key); + let{achievement_methods}=this.state; + let newachievement_methods=achievement_methods; + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + var value=parseFloat(e.target.value); + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + let value=parseFloat(e.target.value); + + if(value>100){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比请输入0~100的数', + meweacoursetype:true, + newshowredvalue:true + }) + value=100 + } + + if(value<0){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能小于0', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + if(value===""||value===null||value===undefined){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能为空', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + newachievement_methods.push(newlist); + this.setState({ + achievement_methods:newachievement_methods + }); + } + Delethandevaluation=(e)=>{ + let {achievement_methods} = this.state; + let id =e.target.getAttribute("index"); + let newachievement_methods=achievement_methods; + newachievement_methods.splice(id,1); + this.setState({ + achievement_methods:newachievement_methods + }); + } + + + EvaluationsSaveonloadgetdata=(id)=>{ + const url = `/ec_course_achievement_methods?ec_course_id=`+id + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + + }).catch(function (error) { + console.log(error); + this.setState({ + spinningstate:false + }) + }); + + + } + ecrestoration=()=>{ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + } + + SaveCourseEvaluationsbottom=()=>{ + let ec_course_id=this.props.match.params.ec_course_id; + this.setState({ + buttomSaveCourseEvaluationsbottom:'', + percentagetype:true + }) + let {newec_course_target_id,achievement_methods} = this.state; + + + for(var j=0; j100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比不能超过总和100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + if(percentagenum<100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比总和要等于100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + for(var i=0;i { + if(response.data.status===0){ + this.setState({ + target_id:null, + newec_course_idbottom:response.data.ec_course_id, + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + // Modallists:response.data.message, + // eacoursetype:true, + Modallists:' ', + meweacoursetype:false, + achievement_methods:undefined, + eacoursesavetypes:false, + newshowredvalue:false, + ismanager:response.data.is_manager + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.EvaluationsSaveonloadgetdata(response.data.ec_course_id); + this.getNavigationData(ec_course_id); + + }else if(response.data.status===-1){ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + Modallists:response.data.message, + eacoursetype:true, + }) + } + }).catch((error) => { + console.log(error) + }) + } + CancelecCourseEvaluationsbottom=()=>{ + this.setState({ + achievement_methods:undefined, + target_id:null, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.getec_course_achievement_methods(); + } + + selectsonFocuslist=(e,key)=>{ + let value =e.course_select_value; + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=key; + let list=totalevaluations_list.evaluations_list; + this.setState({ + evaluations_lists: evaluation_subitems_list[value], + evaluation_subitems_lists: evaluation_subitems_list[value][0] + }); + + if(newachievement_methods.length===0){ + for(var i=0; i0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + this.setState({ + eacoursetype:false + }) + } + render() { + const Option = Select.Option; + let {schooldata,achievement_list,spinningstate,evaluations_list,evaluations_lists,newec_course_target_id,achievement_methods,ec_course_target_name,buttomSaveCourseEvaluationsbottom,sequenceid,target_id, + titlemessages, + Modallists, + eacoursetype, + eacoursesavetypes, + methodologytype, + newec_course_idbottom, + meweacoursetype, + percentagetype, + ismanager + } = this.state; + return ( +
                  +
                  + +
                  +
                  {Modallists}
                  +
                  +
                  + 取消 + 确定 +
                  +
                  + + {/*导航*/} + {/*
                  */} + + {/*

                  */} + {/*课程列表 > */} + {/* {schooldata.ec_course_name} 课程考核方式与数据来源*/} + {/*/!* *!/*/} + {/*/!* 导出培养目标 *!/*/} + {/*导出策略*/} + {/*

                  */} + + {/*
                  */} + {/*课程考核标准*/} + {/*(请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统)*/} + {/*在线课堂:{course_name}*/} + {/*导入课堂数据*/} + {/*
                  */} + + {/*
                  */} + {/**/} + + {/*
                  */} + + {/*

                  */} + {/* 课程体系 >*/} + {/* {schooldata.ec_course_name} */} + {/*

                  请结合本课程的教学情况,修改说明每个课程目标的评价环节和评估方式 window.elasticLayer(3533)}>查看详情
                  */} + + {/* /!*课程考核方式与数据来源*!/*/} + {/* /!* *!/*/} + {/* /!* 导出培养目标 *!/*/} + {/* */} + {/* 导出评价方法*/} + {/* */} + {/*

                  */} + + {/*
                  */} + {/* /!*课程目标达成方法*!/*/} + {/* 1.课程目标*/} + {/* 2.课程考核方式与数据来源*/} + {/* 3.成绩等级设置*/} + {/* 4.课程目标评价方法*/} + {/* 5.课程达成评价结果*/} + {/* (各环节平均得分*占比)之和/(各环节总分*占比)之和*/} + {/*
                  */} + + {/*
                  */} + +
                  + +

                  + 课程目标 + 评价环节 + 数据内容 + + 操作 + + 评价占比 + 支撑总分值 +

                  + + { + achievement_list.length===0?}/>:achievement_list.map((item,key)=>{ + return( +
                  + { + item.target_evaluate_data.length===0? +
                • +
                  + {key+1} + + + + + + + + +
                  +
                  + +
                  +
                  +
                  + + + +
                  +
                  + + +
                  +
                  + +
                  +
                  + + {/* 修改start*/} +
                  +
                  + {/*
                  */} +
                  +
                  + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
                  +
                  + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + return( +
                  +
                  + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} id={itemkey} style={{ width: '11%' }} placeholder="请输入占比"/> + % + +
                  + + + + + + +
                  +
                  +
                  +
                  +
                  + ) + }) + } + {Modallists} +
                  +
                  保存
                  +
                  取消
                  +
                  +
                  +
                  + {/* 修改end*/} + + + +
                • + :item.target_evaluate_data.map((i,k)=>{ + return( +
                • +
                  + {key-k===key?key+1:""} + + + {i.evaluate_name} + + + { + i.evaluation_relates_data.map((y,e)=>{ + return( +
                  {y.evaluation_relates_name+" "}
                  + ) + }) + } +
                  + { + key-k===key? +
                  +
                  + +
                  +
                  +
                  : + +
                  +
                  + +
                  +
                  +
                  + } + + + +
                  {i.percentage+"%"}
                  +
                  + + +
                  {i.score}
                  +
                  + +
                  +
                  + {/* 修改start*/} +
                  +
                  +
                  +
                  + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
                  +
                  + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + + return( +
                  +
                  + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} + id={itemkey} style={{ width: '11%' }} + placeholder="请输入占比"/> + % + +
                  + + + + + + +
                  +
                  +
                  +
                  +
                  + ) + }) + } + {Modallists} +
                  +
                  保存
                  +
                  取消
                  +
                  +
                  +
                  + {/* 修改end*/} + +
                • + + ) + + }) + } +
                  + ) + }) + } +
                  + +
                  +
                  + ); + } +} + +export default SnackbarHOC() (EcCourseEvaluationsbottom); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js new file mode 100644 index 000000000..ead6e4c29 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js @@ -0,0 +1,405 @@ +import React, { Component } from 'react'; + +import axios from 'axios'; +import { Spin } from 'antd'; + +import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; + +import { SnackbarHOC,getImageUrl } from 'educoder' + +import { Pagination,Upload,Modal,Checkbox } from 'antd'; + +import EcTitleCourseEvaluations from '../../ecTitle/ecTitle' + +import 'antd/dist/antd.css'; + +import './ecStudentList.css'; + +const $ = window.$; + +class EcStudentList extends Component { + constructor(props) { + super(props) + this.state={ + majorschoollist:undefined, + titlemessage:"提示", + // ecComponentState:"ecStudentList", + visible:false, + Modallist:'', + Modallisttypes:0, + studentall:false, + student_id:undefined, + Modallisttypess:0, + ismanager:false, + isSpin:false + } + } + componentDidMount(){ + window.document.title = '学生列表'; + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + + // const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data'; + // axios.get(url, { + // withCredentials: true, + // }).then((response) => { + // if(response.status===200){ + // this.setState({ + // majorschoollist:response.data, + // ismanager:response.data.ismanager, + // }) + // } + // }) + // .catch(function (error) { + // console.log(error); + // }); + // let majorschoollist={ + // ec_students: [{index: 1, student_name: "同意", student_id: "s20111458"}, + // {index: 1, student_name: "同意", student_id: "s20111458"}, + // {index: 2, student_name: "涛哥", student_id: "2011554f4"}, + // {index: 3, student_name: "例如", student_id: "20154787b"}, + // {index: 4, student_name: "问问", student_id: "201548580014"}, + // {index: 5, student_name: "嗯嗯", student_id: "2015748912321234"}, + // {index: 6, student_name: "让人", student_id: "20157456"}, + // {index: 7, student_name: "方法", student_id: "20159658"}, + // {index: 8, student_name: "全球", student_id: "20159632"}, + // {index: 9, student_name: "是说", student_id: "20154512"}, + // {index: 10, student_name: "谷歌", student_id: "20157932"}, + // {index: 11, student_name: "版本", student_id: "20159635"}, + // {index: 12, student_name: "捏捏", student_id: "20153451"}, + // ], + // import_url: "/ec_major_schools/3/academic_years/10/import_students", + // show_name: true, + // template_url: "/attachments/download/227528/01_学生列表导入模板.xls", + // total_page: 1 + // } + // this.setState({ + // majorschoollist:majorschoollist + // }) + } + uploadcomponentDidMount(){ + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data'; + axios.get(url, { + withCredentials: true, + }).then((response) => { + if(response.status===200){ + this.setState({ + majorschoollist:response.data, + ismanager:response.data.ismanager, + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + + windowsgoblack=()=>{ + window.history.go(-1) + } + + + uploadfile=(file)=>{ + this.setState({isSpin:true}) + let {majorschoollist}=this.state; + let Url =majorschoollist.import_url; + const form = new FormData(); + form.append('file', file.file); + axios.post(Url,form + ).then((response) => { + if(response.data.status===1){ + // message.success('已成功导入'+response.data.count+"条数据!"); + this.setState({ + // titlemessage: response.data.message+"(支撑关系变更)", + Modallist: '已成功导入'+response.data.count+"条数据!", + Modallisttype:true, + Modallisttypes:1, + isSpin:false + }) + }else if(response.data.status===0){ + // message.warning(response.data.message); + this.setState({ + // titlemessage: response.data.message+"(支撑关系变更)", + Modallist:response.data.message, + Modallisttype:true, + Modallisttypes:0, + isSpin:false + }) + } + }).catch((error) => { + console.log(error) + }) + } + hidemodeldelete=()=>{ + let {Modallisttypes}=this.state; + this.setState({ + Modallisttype:false, + Modallist:'', + Modallisttypess:0 + }) + if(Modallisttypes===1){ + // window.location.reload(); + this.uploadcomponentDidMount(); + } + } + + showecStudentList=(page)=>{ + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data?page='+page; + axios.get(url, { + withCredentials: true, + }).then((response) => { + if(response.status===200){ + this.setState({ + majorschoollist:response.data, + ismanager:response.data.ismanager, + }) + } + }).catch(function (error) { + console.log(error); + }); + } + + onChangestudentall=(e)=>{ + let {majorschoollist}=this.state; + let mewmajorschoollist=majorschoollist + for(var i=0; i{ + let {majorschoollist,studentall}=this.state; + let mewmajorschoollist=majorschoollist; + let newstudentall=studentall; + if(e.target.checked===false){ + newstudentall=false + } + for(var i=0; i{ + let {majorschoollist,studentall} =this.state; + let studentalltype=0 + for(var i=0; i{ + let {majorschoollist,studentall} =this.state; + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + let newstudent_id=[]; + if(studentall===false){ + for(var i=0; i { + if(response.data.status===1){ + this.setState({ + // Modallist: "删除成功!", + // Modallisttype:true, + Modallisttypes:1, + Modallisttypess:0 + }) + this.hidemodeldelete(); + } + }).catch((error) => { + console.log(error) + }) + } + + render() { + let { + majorschoollist, + Modallisttype, + titlemessage, + Modallist, + studentall, + student_id, + Modallisttypess, + ismanager + }=this.state; + // ec_students: [] + // import_url: "/ec_major_schools/:1/academic_years/:1/import_students" + // template_url: "javascript:void(0);" + // total_page: 0 + const uploadProps = { + name: 'file', + + onPreview(file) { + // dispatch({ type: `${nameSpace}/updateState`, payload: { uploadPreviewVisible: true, uploadPreviewImage: file.url || file.thumbUrl } }); + }, + onChange(file) { + // dispatch({ type: `${nameSpace}/updateState`, payload: { fileList: fileList } }); + }, + onRemove(option) { + }, + customRequest: file => { + this.uploadfile(file) + } + } + return ( +
                  + +
                  +
                  {Modallist}
                  +
                  +
                  + 取消 + { + Modallisttypess===0?确定:确定 + } + +
                  +
                  +
                  +
                  + 学生列表 + 返回 +
                  + +
                  + +
                  学生列表( + {majorschoollist===undefined?"":majorschoollist.total_student} + ) +
                  提供模板支持导入学生信息(请先下载模板) window.elasticLayer(3533)}>查看详情
                  +
                  + +
                  + {ismanager===false?"": + 请使用导入模板(点击下载),将本学年所有参与的学生导入系统,以便录入教学活动相关数据 + } + + {ismanager===false?"": + 导入 + } + +
                  + +
                  + {ismanager===false?"":
                  + 删除 +
                  } +
                  + +
                  +

                  + + + 序号 + + 姓名 + 学号 +

                  + + +
                    + { + majorschoollist===undefined? +
                    +

                    +

                    学生数据为空,请导入数据

                    +
                    + :majorschoollist.ec_students.length===0? +
                    +

                    +

                    学生数据为空,请导入数据

                    +
                    :majorschoollist.ec_students.map((item,key)=>{ + // console.log(item) + return( +
                  • + + + {item.index} + + {item.student_name} + {item.student_id} +
                  • + ) + }) + } + +
                  + +
                  + { + majorschoollist===undefined?"":majorschoollist.total_page===0||majorschoollist.total_student<51?"": + } +
                  +
                  +
                  +
                  +
                  + +
                  + + ) + + } +} + +export default SnackbarHOC() (EcStudentList); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css b/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css new file mode 100644 index 000000000..0dfc22b99 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css @@ -0,0 +1,44 @@ +.pagelistStudentList{ + position: absolute; + padding-left: 40%; +} + +.relative{ + position: relative; +} +.changestudent{ + position: absolute; + top: 13px; + left: 50px; +} +.changestudents{ + position: absolute; + top: -1px; + left: 50px; +} +.padbottom{ + padding-bottom: 0px; +} + +.deletelist{ + margin-top: 10px; + margin-bottom: 10px; +} + +.deletelist:hover{ + color:#afafaf !important; +} + +.deletebth{ + width:64px; + height:24px; + border:1px solid #afafaf; + border-radius:2px; + color:#afafaf; + background:#fff; + line-height:24px; +} + +.mt60{ + margin-top:60px; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/nodata.png b/public/react/src/modules/ecs/subroute/ecStudentList/nodata.png new file mode 100644 index 000000000..15a9e522f Binary files /dev/null and b/public/react/src/modules/ecs/subroute/ecStudentList/nodata.png differ diff --git a/public/react/src/modules/forums/MemoDetailMDEditor.js b/public/react/src/modules/forums/MemoDetailMDEditor.js index 78aa54182..6e2563b9b 100644 --- a/public/react/src/modules/forums/MemoDetailMDEditor.js +++ b/public/react/src/modules/forums/MemoDetailMDEditor.js @@ -130,7 +130,7 @@ class MemoDetailMDEditor extends Component { } } render() { - const { match, history, memo, placeholder, className } = this.props + const { match, history, memo, placeholder, className, imageExpand } = this.props const { isInited, errorMsg } = this.state if (!memo) { return
                  @@ -185,7 +185,8 @@ class MemoDetailMDEditor extends Component { ` } */} -
                  diff --git a/public/react/src/modules/forums/MemoNew.js b/public/react/src/modules/forums/MemoNew.js index 476d41a8a..2f6eb196d 100644 --- a/public/react/src/modules/forums/MemoNew.js +++ b/public/react/src/modules/forums/MemoNew.js @@ -101,9 +101,9 @@ function create_editorMD(id, width, high, placeholder, imageUrl, callback){ }); $("#"+ 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.setCursor(__Cursor.line, __Cursor.ch-3); editorName.cm.focus(); }); $("[type=\"inline\"]").attr("title", "行内公式"); @@ -553,7 +553,7 @@ class MemoNew extends Component { return attachments; } handleChange = (info) => { - if (info.file.status === 'uploading' || info.file.status === 'done') { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) @@ -561,7 +561,7 @@ class MemoNew extends Component { } } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.props.confirm({ // title: '确定要删除这个附件吗?', content: '是否确认删除?', diff --git a/public/react/src/modules/forums/RightSection.css b/public/react/src/modules/forums/RightSection.css index f151585c8..a31b1dff8 100644 --- a/public/react/src/modules/forums/RightSection.css +++ b/public/react/src/modules/forums/RightSection.css @@ -10,9 +10,12 @@ /*margin-right: 35px;*/ } .search-newysl { - width:237px!important; + height: 30px; margin-bottom: 30px; +} +.search-newyslw{ + width:237px!important; } .search-new-input { padding-left: 16px; diff --git a/public/react/src/modules/help/AboutUs.js b/public/react/src/modules/help/AboutUs.js new file mode 100644 index 000000000..06198418c --- /dev/null +++ b/public/react/src/modules/help/AboutUs.js @@ -0,0 +1,54 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Card } from "antd"; +import axios from 'axios'; + +import { MarkdownToHtml } from 'educoder'; + +class AboutUs extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + content: null + } + } + + componentDidMount(){ + window.document.title = "关于我们"; + this.getContent(); + } + + getContent(){ + axios.get("/helps/about.json").then((result) => { + if(result){ + this.setState({ + content: result.data.content, + loading: false + }) + } + }).catch((error) => { + console.log(error); + this.setState({ loading: false }); + }) + } + + render() { + let { loading, content } = this.state; + + return ( +
                  +
                  + +
                  + { content && } +
                  +
                  +
                  +
                  + ) + } +} + +export default AboutUs; \ No newline at end of file diff --git a/public/react/src/modules/help/Agreement.js b/public/react/src/modules/help/Agreement.js new file mode 100644 index 000000000..4e483b719 --- /dev/null +++ b/public/react/src/modules/help/Agreement.js @@ -0,0 +1,54 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Card } from "antd"; +import axios from 'axios'; + +import { MarkdownToHtml } from 'educoder'; + +class Agreement extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + content: null + } + } + + componentDidMount(){ + window.document.title = "服务协议"; + this.getContent(); + } + + getContent(){ + axios.get("/helps/agreement.json").then((result) => { + if(result){ + this.setState({ + content: result.data.content, + loading: false + }) + } + }).catch((error) => { + console.log(error); + this.setState({ loading: false }); + }) + } + + render() { + let { loading, content } = this.state; + + return ( +
                  +
                  + +
                  + { content && } +
                  +
                  +
                  +
                  + ) + } +} + +export default Agreement; \ No newline at end of file diff --git a/public/react/src/modules/help/ContactUs.css b/public/react/src/modules/help/ContactUs.css new file mode 100644 index 000000000..e516196e6 --- /dev/null +++ b/public/react/src/modules/help/ContactUs.css @@ -0,0 +1,24 @@ +.contact-us-container { + +} +.contact-us-container .contact-item { + padding: 20px 15px; + border-bottom: 1px solid #EEEEEE; +} +.contact-us-container .contact-item:first-child { + padding-top: 0; +} +.contact-us-container .contact-item:last-child { + border-bottom: unset; +} + +.contact-us-container .contact-item-label { + font-size: 16px; + padding-bottom: 10px; +} +.contact-us-container .contact-item-content { + margin-left: 10px; +} +.contact-us-container .contact-item-content .ant-row { + margin-top: 10px; +} \ No newline at end of file diff --git a/public/react/src/modules/help/ContactUs.js b/public/react/src/modules/help/ContactUs.js new file mode 100644 index 000000000..04e3404fe --- /dev/null +++ b/public/react/src/modules/help/ContactUs.js @@ -0,0 +1,89 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Card, Row, Col } from "antd"; +import axios from 'axios'; + +import './ContactUs.css'; + +class ContactUs extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + contacts: null, + address: null + } + } + + componentDidMount(){ + window.document.title = "联系我们"; + this.getData(); + } + + getData(){ + axios.get("/helps/contact.json").then((result) => { + if(result){ + this.setState({ + contacts: result.data.contacts, + address: result.data.address, + loading: false + }) + } + }).catch((error) => { + console.log(error); + this.setState({ loading: false }); + }) + } + + render() { + let { loading, contacts, address } = this.state; + + return ( +
                  +
                  + +
                  + { + contacts && contacts.map((item, _key) => { + return ( +
                  +
                  { item.type }
                  +
                  + +
                  { item.name } + + + QQ: + { item.qq } + + + Email: + { item.mail } + + + + ) + }) + } + { + address && ( +
                  +
                  公司地址
                  +
                  + +
                  { address } + + + + ) + } + + + + + ) + } +} + +export default ContactUs; \ No newline at end of file diff --git a/public/react/src/modules/help/Cooperatives.css b/public/react/src/modules/help/Cooperatives.css new file mode 100644 index 000000000..1ab232a26 --- /dev/null +++ b/public/react/src/modules/help/Cooperatives.css @@ -0,0 +1,17 @@ +.cooperatives-container { + +} + +.cooperatives-container .cooperative-item-title { + margin-bottom: 20px; + font-size: 16px; +} +.cooperatives-container .cooperative-item-list-item { + padding: 10px 0; + height: 60px; + border: 1px solid #eee; +} +.cooperatives-container .cooperative-item-list-item img { + width: 100%; + height: 100%; +} \ No newline at end of file diff --git a/public/react/src/modules/help/Cooperatives.js b/public/react/src/modules/help/Cooperatives.js new file mode 100644 index 000000000..b64657488 --- /dev/null +++ b/public/react/src/modules/help/Cooperatives.js @@ -0,0 +1,82 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { List, Card } from "antd"; +import axios from 'axios'; +import { getImageUrl } from 'educoder'; + +import './Cooperatives.css'; + +class Cooperatives extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + data: [ + { name: "产学联盟" }, + { name: "知名企业" }, + { name: "各类院校" } + ] + } + } + + componentDidMount(){ + window.document.title = "合作伙伴"; + this.getCooperatives(); + } + + getCooperatives(){ + axios.get("/helps/cooperatives.json").then((result) => { + if(result){ + this.setState({ + data: result.data.data, + loading: false + }) + } + }).catch((error) => { + console.log(error); + this.setState({ loading: false }); + }) + } + + render() { + let { loading, data } = this.state; + + return ( +
                  +
                  + +
                  + { + data && data.length > 0 && data.map((item, _key) => { + return ( +
                  +
                  { item.name }
                  +
                  + ( + +
                  + + + +
                  +
                  + )} + /> +
                  +
                  + ) + }) + } +
                  +
                  +
                  +
                  + ) + } +} + +export default Cooperatives; \ No newline at end of file diff --git a/public/react/src/modules/help/Feedback.css b/public/react/src/modules/help/Feedback.css new file mode 100644 index 000000000..081370254 --- /dev/null +++ b/public/react/src/modules/help/Feedback.css @@ -0,0 +1,7 @@ +.feedback-container { + +} +.feedback-container .feedback-message { + line-height: 26px; + color: #999999; +} \ No newline at end of file diff --git a/public/react/src/modules/help/Feedback.js b/public/react/src/modules/help/Feedback.js new file mode 100644 index 000000000..c7f13f809 --- /dev/null +++ b/public/react/src/modules/help/Feedback.js @@ -0,0 +1,51 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { Link } from 'react-router-dom'; +import { Card, Form } from "antd"; + +import "./Feedback.css"; + +import FeedbackForm from './FeedbackForm'; +const NewFeedbackForm = Form.create({ name: 'feedback_form' })(FeedbackForm); + +class Feedback extends React.Component { + constructor (props) { + super(props); + } + + componentDidMount() { + window.document.title = "意见反馈"; + } + + componentDidUpdate(prevProps) { + if (prevProps.current_user !== this.props.current_user) { + if(!this.props.checkIfLogin()) { + this.props.showLoginDialog(); + } + } + } + + render() { + return ( +
                  +
                  + +
                  +
                  + 想对我们的平台提供功能建议?
                  + 发现网页中的问题或bug想告诉我们?
                  + 期望与我们展开合作?
                  + 在这里把你想说的一切告诉我们吧? +
                  +
                  * 看看帮助中心是否有你想要的答案
                  + + +
                  +
                  +
                  +
                  + ) + } +} + +export default Feedback; \ No newline at end of file diff --git a/public/react/src/modules/help/FeedbackForm.js b/public/react/src/modules/help/FeedbackForm.js new file mode 100644 index 000000000..ae2c4e095 --- /dev/null +++ b/public/react/src/modules/help/FeedbackForm.js @@ -0,0 +1,87 @@ +import React from 'react'; +import { Form, Input, Radio, Button } from "antd"; +import axios from 'axios'; + +const { TextArea } = Input; + +class FeedbackForm extends React.Component { + constructor (props) { + super(props); + } + + handleSubmit = e => { + e.preventDefault(); + + this.props.form.validateFields((err, fieldsValue) => { + if(err){ return } + + axios.post("/helps/feedback.json", fieldsValue) + .then((result) => { + if (result.status === 200 && result.data.status === 0) { + this.props.history.push(`/messages/${this.props.current_user.login}/message_detail?target_ids=1`); + } + }).catch((error) => { + console.log(error) + }) + }) + } + + render() { + const { getFieldDecorator } = this.props.form; + + return ( +
                  +
                  + + {getFieldDecorator('question_kind', { + initialValue: "登录注册", + rules: [ + { + required: true, + message: '不能为空', + }, + ], + })( + + 登录注册 + 信息认证 + 实训编程 + 实训课程 + 课堂 + 其它 + + )} + + + + {getFieldDecorator('url', { + rules: [ + { + required: true, + message: '不能为空', + }, + ], + })()} + + + + {getFieldDecorator('description', { + rules: [ + { + required: true, + message: '不能为空', + }, + ], + })(*/} - {/* cm monaco 切换 */} - {/* */} - + {this.props.readRepoTimeout === true ? : + +
                  + {/**/} + {/* cm monaco 切换 */} + {/* */} + +
                  + }
                  diff --git a/public/react/src/modules/page/main/CodeRepositoryViewContainer.js b/public/react/src/modules/page/main/CodeRepositoryViewContainer.js index 8efe7b0e1..279402e66 100644 --- a/public/react/src/modules/page/main/CodeRepositoryViewContainer.js +++ b/public/react/src/modules/page/main/CodeRepositoryViewContainer.js @@ -1,288 +1,322 @@ - -import React, { Component } from 'react'; - -import CodeRepositoryView from './CodeRepositoryView' - -import axios from 'axios' - -import './CodeRepositoryView.css' - -// 自己处理path,加上父节点的path, 这里是处理树节点了,所以是set key -function addPrePath(treeData, parentNodePath) { - return treeData.map(item => { - return { - ...item, - key: `${parentNodePath}/${item.name}` - } - }) -} -function getNewTreeData(treeData, curKey, child, level) { - const loop = (data) => { - data.forEach((item) => { - // 这里不能用indexOf 同一级可能出现test目录和test.py文件 - if (item.key == curKey) { - child = addPrePath(child, curKey); - item.children = child; - } else { - if (item.children) { - loop(item.children); - } - } - }); - }; - loop(treeData); -} - -function fileData2TreeData(repoFilesData) { - const fileTreeData = []; - repoFilesData.forEach((item) => { - if (item.kind === 'file') { - fileTreeData.push({ - key: item.path, - name: item.name, - isLeaf: true - }) - } else { - fileTreeData.push({ - key: item.path, - name: item.name, - // isLeaf: false - }) - } - }) - return fileTreeData; -} - -class CodeRepositoryViewContainer extends Component { - - constructor(props) { - super(props) - - this.showFilesDrawer = this.showFilesDrawer.bind(this) - this.onRepositoryViewExpand = this.onRepositoryViewExpand.bind(this) - - this.state = { - drawerOpen: false, - loadingFirstRepoFiles: false, - fileTreeData: "", - fileTreeSelectedKeys: [], - codeRepositoryViewExpanded: false, - tabIndex: 0, - - settingDrawerOpen: false - } - } - showSettingDrawer = (open) => { - this.setState({settingDrawerOpen: open}) - } - tabIndexChange = (index) => { - this.setState({tabIndex: index}); - } - onRepositoryViewExpand() { - window.repository_extend_and_zoom(); - this.setState({ - evaluateViewExpanded: !this.state.evaluateViewExpanded - }, () => { - setTimeout(()=>{ - window.__tpiOnResize() - }, 300) - }) - } - - showFilesDrawer(open) { - if (this.props.loading === true) { - return; - } - if (!this.state.fileTreeData) { - this.fetchRepoFiles(); - } - - this.setState({ - drawerOpen: open, - }) - } - - componentWillReceiveProps(newProps, oldProps) { - - } - componentDidMount() { - - } - - componentDidUpdate(prevProps, prevState, snapshot) { - const { game, challenge } = this.props - if (this.props.game && (!prevProps.game || prevProps.game.identifier !== this.props.game.identifier) ) { - this.setState({ - fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ] - }) - // 初始化 - } else if (this.state.fileTreeSelectedKeys.length === 0 && challenge && challenge.path) { - this.setState({ - fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ] - }) - } else if (challenge && prevProps && prevProps.challenge - && challenge.pathIndex != prevProps.challenge.pathIndex - && challenge.pathIndex !== -1) { - this.setState({ - fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[challenge.pathIndex] : challenge.path ] - }) - } - } - - handleDialogClose() { - this.setState({ - dialogOpen: false - }) - } - onLoadData = (treeNode) => { - if (treeNode.props.children && treeNode.props.children.length) { - return new Promise((resolve) => { - resolve(); - }); - } - return new Promise((resolve, reject) => { - this.fetchRepoFiles(treeNode, resolve, reject) - }); - } - map2OldData = (treeData) => { - if (!treeData || treeData.length === 0) return treeData; - treeData = treeData.map(item => { - return { - kind: item.type == "blob" ? "file" : "dir", // blob->file tree->dir - path: item.name, - name: item.name - } - }) - return treeData; - } - - fetchRepoFiles(treeNode, resolve, reject) { - // http://localhost:3000/api/v1/games/829al3mst4fy/entries?path=src/step1&rev=master - if (!this.props.challenge || !this.props.game) { - return; - } - // var ar = this.props.challenge.path.split('/'); - // ar.length = ar.length - 2; - // var _path = ar.join('/'); - var _path = treeNode ? treeNode.props.eventKey : '' ; - if (_path.charAt(0) === '/') { - _path = _path.substring(1) - } - // var url = `/api/v1/games/${this.props.game.identifier}/entries?path=${_path}&rev=master&gpid=${this.props.myshixun.gpid}` - let url = `/myshixuns/${this.props.myshixun.identifier}/repository.json` - - - if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { - this.setState({ - loadingFirstRepoFiles: true, - }) - } - var that = this; - axios.post(url, { - path: _path - // withCredentials: true, - }) - .then((response) => { - const repoFilesData = this.map2OldData(response.data.trees) - if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { // 还没树节点,没加载过 - - const fileTreeData = fileData2TreeData(repoFilesData) - this.setState({ - fileTreeData, - loadingFirstRepoFiles: false, - }); - } else { - var _treeNode = treeNode; - var _eventKey = _treeNode.props.eventKey; - - const fileTreeData = that.state.fileTreeData; - // 新的数组放置到treenode下 - - const tempFileTreeData = fileData2TreeData(repoFilesData) - - getNewTreeData(fileTreeData, _eventKey, tempFileTreeData, 2); - this.setState({ - fileTreeData, - }) - } - - resolve && resolve(); - - }) - .catch(function (error) { - console.log(error); - reject && reject(); - }); - } - onTreeSelect = (selectedKeys, info) => { - const isLeaf = info.node.props.isLeaf; - if (isLeaf) { // 叶子节点 - selectedKeys.length && this.setState({ - fileTreeSelectedKeys: selectedKeys - }) - const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props; - - const nodePath = info.node.props.eventKey; - // 设置pathIndex为-1,那么代码文件下拉可以切回可编辑的文件 - if (!challenge.multiPath) { // 单path任务 多path任务 path是数组 - if (challenge.path.trim() == nodePath.trim()) { - if (challenge.pathIndex === 0) { - showSnackbar(`当前编辑文件已经是${nodePath}`) - } else { - onPathChange(0) - } - return; - } else { - onPathChange(-1) - } - } else { - let isCurrentFile = false; - let cur_index = -1; - if (challenge.path && challenge.path.forEach) { - challenge.path.forEach((item, index) => { - if (nodePath == item) { - isCurrentFile = true; - cur_index = index; - } - }) - } - if (isCurrentFile) { - onPathChange(cur_index) - showSnackbar(`当前编辑文件已经是${nodePath}`) - } else { - onPathChange(-1) - } - } - if (nodePath) { - const filetype = nodePath.split('.').pop().toLowerCase(); - if (filetype == 'jpg' || filetype == 'png' || filetype == 'gif' || filetype == 'jpeg' - || filetype == 'jar' - || filetype == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') { - showSnackbar(`不支持加载${filetype}类型的文件。`) - return; - } - fetchRepositoryCode(null, nodePath, 1); - } else { - console.error('no eventKey:', info.node) - } - } - } -// /shixuns/mnf6b7z3/shixun_discuss?challenge_id=88 - render() { - - return ( - - ); - } -} - -export default CodeRepositoryViewContainer; + +import React, { Component } from 'react'; + +import CodeRepositoryView from './CodeRepositoryView' + +import axios from 'axios' + +import './CodeRepositoryView.css' + +// 自己处理path,加上父节点的path, 这里是处理树节点了,所以是set key +function addPrePath(treeData, parentNodePath) { + return treeData.map(item => { + return { + ...item, + key: `${parentNodePath}/${item.name}` + } + }) +} +function getNewTreeData(treeData, curKey, child, level) { + const loop = (data) => { + data.forEach((item) => { + // 这里不能用indexOf 同一级可能出现test目录和test.py文件 + if (item.key == curKey) { + child = addPrePath(child, curKey); + item.children = child; + } else { + if (item.children) { + loop(item.children); + } + } + }); + }; + loop(treeData); +} + +function fileData2TreeData(repoFilesData) { + if(repoFilesData!=null){ + const fileTreeData = []; + repoFilesData.forEach((item) => { + if (item.kind === 'file') { + fileTreeData.push({ + key: item.path, + name: item.name, + isLeaf: true + }) + } else { + fileTreeData.push({ + key: item.path, + name: item.name, + // isLeaf: false + }) + } + }) + return fileTreeData; + } + +} + +class CodeRepositoryViewContainer extends Component { + + constructor(props) { + super(props) + + this.showFilesDrawer = this.showFilesDrawer.bind(this) + this.onRepositoryViewExpand = this.onRepositoryViewExpand.bind(this) + + this.state = { + drawerOpen: false, + loadingFirstRepoFiles: false, + fileTreeData: "", + fileTreeSelectedKeys: [], + codeRepositoryViewExpanded: false, + tabIndex: 0, + + settingDrawerOpen: false + } + } + showSettingDrawer = (open) => { + this.setState({settingDrawerOpen: open}) + } + tabIndexChange = (index) => { + this.setState({tabIndex: index}); + } + onRepositoryViewExpand() { + window.repository_extend_and_zoom(); + this.setState({ + evaluateViewExpanded: !this.state.evaluateViewExpanded + }, () => { + setTimeout(()=>{ + window.__tpiOnResize() + }, 300) + }) + } + + showFilesDrawer(open) { + if (this.props.loading === true) { + return; + } + if (!this.state.fileTreeData) { + this.fetchRepoFiles(); + } + + this.setState({ + drawerOpen: open, + }) + } + loadRepoFiles = () => { + if (!this.state.fileTreeData) { + this.fetchRepoFiles(); + } + } + + componentWillReceiveProps(newProps, oldProps) { + + } + componentDidMount() { + + } + + componentDidUpdate(prevProps, prevState, snapshot) { + const { game, challenge } = this.props + if (this.props.game && (!prevProps.game || prevProps.game.identifier !== this.props.game.identifier) ) { + this.setState({ + fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ] + }) + // 初始化 + } else if (this.state.fileTreeSelectedKeys.length === 0 && challenge && challenge.path) { + this.setState({ + fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[0] : challenge.path ] + }) + } else if (challenge && prevProps && prevProps.challenge + && challenge.pathIndex != prevProps.challenge.pathIndex + && challenge.pathIndex !== -1) { + this.setState({ + fileTreeSelectedKeys: [ challenge.multiPath ? challenge.path[challenge.pathIndex] : challenge.path ] + }) + } + } + + handleDialogClose() { + this.setState({ + dialogOpen: false + }) + } + onLoadData = (treeNode) => { + if (treeNode.props.children && treeNode.props.children.length) { + return new Promise((resolve) => { + resolve(); + }); + } + return new Promise((resolve, reject) => { + this.fetchRepoFiles(treeNode, resolve, reject) + }); + } + map2OldData = (treeData) => { + if (!treeData || treeData.length === 0) return treeData; + treeData = treeData.map(item => { + return { + kind: item.type == "blob" ? "file" : "dir", // blob->file tree->dir + path: item.name, + name: item.name + } + }) + return treeData; + } + + fetchRepoFiles(treeNode, resolve, reject) { + // http://localhost:3000/api/v1/games/829al3mst4fy/entries?path=src/step1&rev=master + if (!this.props.challenge || !this.props.game) { + return; + } + // var ar = this.props.challenge.path.split('/'); + // ar.length = ar.length - 2; + // var _path = ar.join('/'); + var _path = treeNode ? treeNode.props.eventKey : '' ; + if (_path.charAt(0) === '/') { + _path = _path.substring(1) + } + // var url = `/api/v1/games/${this.props.game.identifier}/entries?path=${_path}&rev=master&gpid=${this.props.myshixun.gpid}` + let url = `/myshixuns/${this.props.myshixun.identifier}/repository.json` + + + if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { + this.setState({ + loadingFirstRepoFiles: true, + }) + } + var that = this; + axios.post(url, { + path: _path + // withCredentials: true, + }) + .then((response) => { + // if (!response) { + // resolve && resolve(); + // return; + // } + const repoFilesData = this.map2OldData(response.data.trees) + if (!this.state.fileTreeData || this.state.fileTreeData.length === 0) { // 还没树节点,没加载过 + + const fileTreeData = fileData2TreeData(repoFilesData) + this.setState({ + fileTreeData, + loadingFirstRepoFiles: false, + }); + } else { + var _treeNode = treeNode; + var _eventKey = _treeNode.props.eventKey; + + const fileTreeData = that.state.fileTreeData; + // 新的数组放置到treenode下 + + const tempFileTreeData = fileData2TreeData(repoFilesData) + + getNewTreeData(fileTreeData, _eventKey, tempFileTreeData, 2); + this.setState({ + fileTreeData, + }) + } + + resolve && resolve(); + + }) + .catch(function (error) { + console.log(error); + reject && reject(); + }); + } + onTreeSelect = (selectedKeys, info) => { + const isLeaf = info.node.isLeaf(); + if (isLeaf) { // 叶子节点 + selectedKeys.length && this.setState({ + fileTreeSelectedKeys: selectedKeys + }) + const { fetchRepositoryCode, onPathChange, showSnackbar, challenge } = this.props; + + const nodePath = info.node.props.eventKey; + let isCurrentFile = false; + // 设置pathIndex为-1,那么代码文件下拉可以切回可编辑的文件 + if (!challenge.multiPath) { // 单path任务 多path任务 path是数组 + if (challenge.path.trim() == nodePath.trim()) { + if (challenge.pathIndex === 0) { + showSnackbar(`当前编辑文件已经是${nodePath}`) + } else { + fetchRepositoryCode(null, nodePath, 1); + onPathChange(0) + } + return; + } else { + onPathChange(-1) + } + } else { + + let cur_index = -1; + if (challenge.path && challenge.path.forEach) { + challenge.path.forEach((item, index) => { + if (nodePath == item) { + isCurrentFile = true; + cur_index = index; + } + }) + } + + if (isCurrentFile) { + if (challenge.pathIndex == cur_index) { + showSnackbar(`当前编辑文件已经是${nodePath}`) + } + onPathChange(cur_index) + // showSnackbar(`当前编辑文件已经是${nodePath}`) + } else { + onPathChange(-1) + } + } + if (nodePath) { + const filetype = nodePath.split('.').pop().toLowerCase(); + if (filetype == 'jpg' || filetype == 'png' || filetype == 'gif' || filetype == 'jpeg' + || filetype == 'jar' + || filetype == 'doc' || filetype == 'pdf' || filetype == 'xsl' || filetype == 'ppt') { + showSnackbar(`不支持加载${filetype}类型的文件。`) + return; + } + fetchRepositoryCode(null, nodePath, 1); + } else { + console.error('no eventKey:', info.node) + } + } + } +// /shixuns/mnf6b7z3/shixun_discuss?challenge_id=88 + render() { + + return ( + + {this.props.isOnlyContainer == true ? + React.Children.map(this.props.children, child => { + if(!child) { + return '' + } + return React.cloneElement(child, Object.assign({...this.state}, { + loadRepoFiles: this.loadRepoFiles, + onTreeSelect: this.onTreeSelect, + onLoadData: this.onLoadData, + })) + }) + + : + + } + + ); + } +} + +export default CodeRepositoryViewContainer; diff --git a/public/react/src/modules/paths/Index.js b/public/react/src/modules/paths/Index.js index 0f3bd349b..813251d28 100644 --- a/public/react/src/modules/paths/Index.js +++ b/public/react/src/modules/paths/Index.js @@ -43,7 +43,7 @@ class Index extends Component{ ()} > - + {/*编辑页面*/} ()} > diff --git a/public/react/src/modules/paths/PathDetail/DetailCards.js b/public/react/src/modules/paths/PathDetail/DetailCards.js index eec340249..d77b35888 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCards.js +++ b/public/react/src/modules/paths/PathDetail/DetailCards.js @@ -336,7 +336,7 @@ class DetailCards extends Component{ showparagraphindex }=this.state; const antIcon = ; - + // console.log("zzz"+this.props.MenuItemsindextype) return(
                  {AccountProfiletype===true? { - showparagraphkey===key&&showparagraphindex===index?
                  + showparagraphkey===key&&showparagraphindex===index?this.props.detailInfoList&&this.props.detailInfoList.allow_statistics===false&&this.props.MenuItemsindextype===2?""::"" @@ -531,6 +531,7 @@ class DetailCards extends Component{ { editbuttomtypeadd===true?'': { this.setState({ selectShixun:false, - page:1, patheditarry:[] }) } - clickShixunchoose=()=>{ - - let{patheditarry,shixuns_listeditlist,shixuns_listedit}=this.state + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } + clickShixunchoose=(patheditarry)=>{ + + let{shixuns_listeditlist,shixuns_listedit}=this.state let newshixuns_listedit=shixuns_listedit; let list=shixuns_listeditlist - if(patheditarry.length===0){ - this.setState({ - Modalstype:true, - Modalstopval:'请选择实训', - cardsModalsave:this.cardsModalsave - }) - - return - } - let url='/paths/append_to_stage.json' axios.post(url,{ shixun_id:patheditarry }).then((response) => { - let newshixun_lists=response.data.shixun_lists; + if(response){ + if(response.data){ + let newshixun_lists=response.data.shixun_lists; + + for(var j=0; j { console.log(error) }); @@ -117,10 +135,11 @@ class DetailCardsEditAndAdd extends Component{ //点击新建阶段 addStage=()=>{ - this.props.editeditbuttomtypes(); this.setState({ editPanel:true }) + this.props.editeditbuttomtypes(); + } //取消新建阶段 @@ -141,38 +160,7 @@ class DetailCardsEditAndAdd extends Component{ }) } - //打开选择实训弹框初始化tag标签和列表 - changeTag=(id,search)=>{ - - this.setState({ - ChooseShixunListshixun_list:[], - page:1, - hometypepvisible:true, - }) - let pathId=this.props.pathid; - - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(id!=0){ - url+="&type="+id; - } - - axios.get(url).then((result)=>{ - if(result.status===200){ - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:id, - ChooseShixunListshixun_list:result.data.shixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - } //勾选实训 shixunhomeworkedit=(list)=>{ @@ -276,77 +264,31 @@ class DetailCardsEditAndAdd extends Component{ let pathId=this.props.pathid; - let url='/stages.json?subject_id='+pathId + let url; + if(this.props.ysldetailcards===undefined){ + url='/stages.json?subject_id='+pathId; + }else{ + url=`/courses/${this.props.coursesId}/course_stages.json`; + } axios.post(url, { name:stage_names, description:newstage_descriptions, shixun_id:shixuns_listeditlist }).then((response) => { // window.location.href = "/paths/" + response.data.subject_id - this.props.getPathCardsLists(); - this.cancelAddState(); this.setState({ stage_nametype:false, descriptiontype:false }) + this.props.getPathCardsLists(); }).catch((error) => { console.log(error) }); } - contentViewScrolladd=(e)=>{ - const {ChooseShixunList}=this.state; - //滑动到底判断 - let newscrollTop=parseInt(e.currentTarget.scrollTop); - let allclientHeight=e.currentTarget.clientHeight+newscrollTop; - - if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ - - if(ChooseShixunList.shixun_list.length===0){ - return - }else{ - // console.log("到达底部"); - this.setState({ - hometypepvisible:true - }) - let pathId=this.props.pathid; - let {search,page,type,ChooseShixunListshixun_list}=this.state; - let newpage=page+1; - let newChooseShixunListshixun_list=ChooseShixunListshixun_list; - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(type!=0){ - url+="&type="+type; - } - axios.get(url).then((result)=>{ - if(result.status===200){ - let list =result.data.shixun_list; - - for(var i=0; i{ - console.log(error); - }) - - } - - } - } onDragEnd (result) { let {shixuns_listedit,shixuns_listeditlist} =this.state; @@ -400,7 +342,7 @@ class DetailCardsEditAndAdd extends Component{ { editPanel &&
                  -
                  +

                  @@ -445,99 +387,13 @@ class DetailCardsEditAndAdd extends Component{ ` } :""} + {selectShixun===true?:""} - - -

                  - -
                  - - - {ChooseShixunList && ChooseShixunList.shixuns_count} - 个实训 - -
                  - this.changeTag(`${type}`,`${search}`)} - style={{width: '115%'}} - > -
                  -
                  -
                    -
                  • 实训名称
                  • -
                  • 使用院校
                  • -
                  • 使用人数
                  • -
                  • 评价等级
                  • -
                  • -
                  - - - {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":
                  - - { - ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ - return( -
                  -
                • - - - -
                • -
                • {item.school_users}
                • -
                • {item.myshixuns_count}
                • -
                • {item.preference}
                • -
                • 详情
                • -
                  - ) - }) - } -
                  -
                  } -
                  - 取消 - 确定 -
                  -
                  - -
                  {/* 可拖拽选择实训列表*/} @@ -632,8 +488,192 @@ class DetailCardsEditAndAdd extends Component{ {this.props.detailInfoList===undefined?"":this.props.detailInfoList.allow_statistics===true?editPanel===false?
                  +点击新建阶段(选择1至多个实训项目,组成一个阶段)
                  :'':''} + {this.props.detailInfoList===undefined&&this.props.isAdmin()&&editPanel===false?
                  + +点击新建阶段(选择1至多个实训项目,组成一个阶段) +
                  :''}
                  ) } } -export default DetailCardsEditAndAdd; \ No newline at end of file +export default DetailCardsEditAndAdd; + + + + +// +// +// +//
                  +// +//
                  +// +// +// {ChooseShixunList && ChooseShixunList.shixuns_count} +// 个实训 +// +//
                  +// this.changeTag(`${type}`,`${search}`)} +// style={{width: '115%'}} +// > +//
                  +//
                  +//
                    +//
                  • 实训名称
                  • +//
                  • 使用院校
                  • +//
                  • 使用人数
                  • +//
                  • 评价等级
                  • +//
                  • +//
                  +// +// +// {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":
                  +// +// { +// ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ +// return( +//
                  +//
                • +// +// +// +//
                • +//
                • {item.school_users}
                • +//
                • {item.myshixuns_count}
                • +//
                • {item.preference}
                • +//
                • 详情
                • +//
                  +// ) +// }) +// } +//
                  +//
                  } +//
                  +// 取消 +// 确定 +//
                  +//
                  +//
                  +//
                  +// contentViewScrolladd=(e)=>{ +// const {ChooseShixunList}=this.state; +// //滑动到底判断 +// let newscrollTop=parseInt(e.currentTarget.scrollTop); +// let allclientHeight=e.currentTarget.clientHeight+newscrollTop; +// +// if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ +// +// if(ChooseShixunList.shixun_list.length===0){ +// return +// }else{ +// // console.log("到达底部"); +// this.setState({ +// hometypepvisible:true +// }) +// let pathId=this.props.pathid; +// let {search,page,type,ChooseShixunListshixun_list}=this.state; +// let newpage=page+1; +// let newChooseShixunListshixun_list=ChooseShixunListshixun_list; +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(type!=0){ +// url+="&type="+type; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// let list =result.data.shixun_list; +// +// for(var i=0; i{ +// console.log(error); +// }) +// +// } +// +// } +// +// } +// +// //打开选择实训弹框初始化tag标签和列表 +// changeTag=(id,search)=>{ +// +// this.setState({ +// ChooseShixunListshixun_list:[], +// page:1, +// hometypepvisible:true, +// }) +// +// let pathId=this.props.pathid; +// +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(id!=0){ +// url+="&type="+id; +// } +// +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:id, +// ChooseShixunListshixun_list:result.data.shixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// } \ No newline at end of file diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js index e98132252..3d1559797 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndEdit.js @@ -1,8 +1,9 @@ import React, { Component } from 'react'; import {getImageUrl} from 'educoder'; -import {Modal,Input,Checkbox,Tooltip,Spin} from "antd"; +import {Modal,Input,Checkbox,Tooltip,Spin,notification} from "antd"; import { DragDropContext,Draggable, Droppable} from 'react-beautiful-dnd'; import Modals from '../../modals/Modals'; +import NewShixunModel from '../../courses/coursesPublic/NewShixunModel'; import '../ShixunPaths.css'; import axios from 'axios'; const $ = window.$; @@ -63,7 +64,7 @@ class DetailCardsEditAndEdit extends Component{ selectShixun:true, patheditarry:[] }) - this.changeTag(0,""); + // this.changeTag(0,""); } //关闭选择实训弹框 cloasShixunBox =()=>{ @@ -79,36 +80,7 @@ class DetailCardsEditAndEdit extends Component{ }) } - //打开选择实训弹框初始化tag标签和列表 - changeTag(id,search){ - this.setState({ - ChooseShixunListshixun_list:[], - page:1, - hometypepvisible:true - }) - let pathId=this.props.pathid; - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 - if(search!="" && search!=undefined){ - url+="&search="+search; - } - if(id!=0){ - url+="&type="+id; - } - axios.get(url).then((result)=>{ - if(result.status===200){ - this.setState({ - ChooseShixunList:result.data, - hometypepvisible:false, - type:id, - search:search, - ChooseShixunListshixun_list:result.data.shixun_list - }) - } - }).catch((error)=>{ - console.log(error); - }) - } shixunhomeworkedit=(list)=>{ @@ -158,22 +130,12 @@ class DetailCardsEditAndEdit extends Component{ } - clickShixunchoose=()=>{ + clickShixunchoose=(patheditarry)=>{ - let{patheditarry,shixuns_listedit,shixuns_listeditlist}=this.state + let{shixuns_listedit,shixuns_listeditlist}=this.state let newshixuns_listedit=shixuns_listedit; let list=shixuns_listeditlist - if(patheditarry.length===0){ - this.setState({ - Modalstype:true, - Modalstopval:'请选择实训', - - }) - - return - } - let url='/paths/append_to_stage.json' axios.post(url,{ shixun_id:patheditarry @@ -184,10 +146,11 @@ class DetailCardsEditAndEdit extends Component{ for(var j=0; j{ - //滑动到底判断 - const {ChooseShixunList}=this.state; - let newscrollTop=parseInt(e.currentTarget.scrollTop); - let allclientHeight=e.currentTarget.clientHeight+newscrollTop; - - if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ - - if(ChooseShixunList.shixun_list.length===0){ - return - }else{ - this.setState({ - hometypepvisible:true - }) - // console.log("到达底部"); - - let {page,type,search,ChooseShixunListshixun_list}=this.state; - - let newpage=page+1; - - let pathId=this.props.pathid; - - let newChooseShixunListshixun_list=ChooseShixunListshixun_list; - - let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage - - if(search!="" && search!=undefined){ - url+="&search="+search; - } - - if(type!=0){ - url+="&type="+type; - } - axios.get(url).then((result)=>{ - if(result.status===200){ - - let list =result.data.shixun_list; - - for(var i=0; i{ - console.log(error); - }) - - - } - - - - } - - } - + showNotification = (description, message = "提示", icon) => { + const data = { + message, + description + } + if (icon) { + data.icon = icon; + } + notification.open(data); + } render(){ let {selectShixun, @@ -481,99 +393,13 @@ class DetailCardsEditAndEdit extends Component{ } :""} + {selectShixun===true?:""} - - -
                  - -
                  - - - {ChooseShixunList && ChooseShixunList.shixuns_count} - 个实训 - -
                  - this.changeTag(`${type}`,`${search}`)} - style={{width: '115%'}} - > -
                  -
                  -
                    -
                  • 实训名称
                  • -
                  • 使用院校
                  • -
                  • 使用人数
                  • -
                  • 评价等级
                  • -
                  • -
                  - - - {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":
                  - - { - ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ - return( -
                  -
                • - - - -
                • -
                • {item.school_users}
                • -
                • {item.myshixuns_count}
                • -
                • {item.preference}
                • -
                • 详情
                • -
                  - ) - }) - } -
                  -
                  } -
                  - 取消 - 确定 -
                  -
                  -
                  -
                  {/* 可拖拽选择实训列表*/} @@ -714,4 +540,191 @@ export default DetailCardsEditAndEdit; //
                  // ) // }) -// } \ No newline at end of file +// } + +// +// +//
                  +// +//
                  +// +// +// {ChooseShixunList && ChooseShixunList.shixuns_count} +// 个实训 +// +//
                  +// this.changeTag(`${type}`,`${search}`)} +// style={{width: '115%'}} +// > +//
                  +//
                  +//
                    +//
                  • 实训名称
                  • +//
                  • 使用院校
                  • +//
                  • 使用人数
                  • +//
                  • 评价等级
                  • +//
                  • +//
                  +// +// +// {ChooseShixunListshixun_list && ChooseShixunListshixun_list.length===0?"":
                  +// +// { +// ChooseShixunListshixun_list && ChooseShixunListshixun_list.map((item,key)=>{ +// return( +//
                  +//
                • +// +// +// +//
                • +//
                • {item.school_users}
                • +//
                • {item.myshixuns_count}
                • +//
                • {item.preference}
                • +//
                • 详情
                • +//
                  +// ) +// }) +// } +//
                  +//
                  } +//
                  +// 取消 +// 确定 +//
                  +//
                  +//
                  +//
                  + +// //打开选择实训弹框初始化tag标签和列表 +// changeTag(id,search){ +// +// this.setState({ +// ChooseShixunListshixun_list:[], +// page:1, +// hometypepvisible:true +// }) +// let pathId=this.props.pathid; +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+1 +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// if(id!=0){ +// url+="&type="+id; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// this.setState({ +// ChooseShixunList:result.data, +// hometypepvisible:false, +// type:id, +// search:search, +// ChooseShixunListshixun_list:result.data.shixun_list +// }) +// } +// }).catch((error)=>{ +// console.log(error); +// }) +// } + +// contentViewScrolledit=(e)=>{ +// //滑动到底判断 +// const {ChooseShixunList}=this.state; +// let newscrollTop=parseInt(e.currentTarget.scrollTop); +// let allclientHeight=e.currentTarget.clientHeight+newscrollTop; +// +// if(e.currentTarget.scrollHeight-allclientHeight===0||e.currentTarget.scrollHeight-allclientHeight===1||e.currentTarget.scrollHeight-allclientHeight===-1){ +// +// if(ChooseShixunList.shixun_list.length===0){ +// return +// }else{ +// this.setState({ +// hometypepvisible:true +// }) +// // console.log("到达底部"); +// +// let {page,type,search,ChooseShixunListshixun_list}=this.state; +// +// let newpage=page+1; +// +// let pathId=this.props.pathid; +// +// let newChooseShixunListshixun_list=ChooseShixunListshixun_list; +// +// let url='/paths/'+pathId+'/choose_subject_shixun.json?page='+newpage +// +// if(search!="" && search!=undefined){ +// url+="&search="+search; +// } +// +// if(type!=0){ +// url+="&type="+type; +// } +// axios.get(encodeURI(url)).then((result)=>{ +// if(result.status===200){ +// +// let list =result.data.shixun_list; +// +// for(var i=0; i{ +// console.log(error); +// }) +// +// +// } +// +// +// +// } +// +// } \ No newline at end of file diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsTemp.js b/public/react/src/modules/paths/PathDetail/DetailCardsTemp.js index 5150d14da..45613db41 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsTemp.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsTemp.js @@ -166,7 +166,7 @@ class DetailCards extends Component{ }) }
                  - +
                  ) } diff --git a/public/react/src/modules/paths/PathDetail/DetailTop.css b/public/react/src/modules/paths/PathDetail/DetailTop.css index 70291c7da..7656bb77d 100644 --- a/public/react/src/modules/paths/PathDetail/DetailTop.css +++ b/public/react/src/modules/paths/PathDetail/DetailTop.css @@ -17,7 +17,7 @@ box-sizing: border-box; } .userNavs{ - line-height: 96px; + line-height: 75px; background: #fff; height:96px; background:rgba(255,255,255,1); @@ -66,4 +66,23 @@ text-overflow: ellipsis; white-space: nowrap; height: 40px; +} + +.mb100{ + margin-bottom: 100px !important; +} +.task-btn-28BE6C{ + background: #28BE6C !important; + color: #fff!important; +} +.mt43{ + margin-top: 43px; +} + +.mb120{ + margin-bottom: 120px !important; +} + +.mb80{ + margin-bottom: 80px !important; } \ No newline at end of file diff --git a/public/react/src/modules/paths/PathDetail/DetailTop.js b/public/react/src/modules/paths/PathDetail/DetailTop.js index 9a460d696..9b85f6498 100644 --- a/public/react/src/modules/paths/PathDetail/DetailTop.js +++ b/public/react/src/modules/paths/PathDetail/DetailTop.js @@ -5,10 +5,12 @@ import SendPanel from "./sendPanel.js"; import { getImageUrl } from 'educoder'; import axios from 'axios'; import Modals from '../../modals/Modals'; +import AccountProfile from"../../user/AccountProfile"; import OpenCourse from './OpenCourse'; -import Jointheclass from '../../modals/Jointheclass' +import Jointheclass from '../../modals/Jointheclass'; import './DetailTop.css'; + const Search = Input.Search; const RadioGroup = Radio.Group; class DetailTop extends Component{ @@ -26,7 +28,9 @@ class DetailTop extends Component{ MenuItemskey:1, courseslist:[], Pathcourseid:undefined, - OpenCourseTypes:false + OpenCourseTypes:false, + putappointmenttype:false, + getappointmenttype:false } } componentDidMount(){ @@ -48,33 +52,43 @@ class DetailTop extends Component{ }) }else{ - this.props.courses.map((item,key)=>{ - if(listtype===false){ - keys=key+1 - if(item.course_status.status===0) { - listtype=true - return ( - courseslist.push(item) - ) - } - } - }) + let type=undefined; + this.props.courses.map((item,key)=>{ - if(listtype===false){ + let arr=[] keys=key+1 if(item.course_status.status===2) { + type=key+1 + arr.push(item) + } + courseslist=arr; + }) + + this.props.courses.map((item,key)=>{ + let arr=[] + if(listtype===false){ + keys=key+1 + if(item.course_status.status===0) { listtype=true - return ( - courseslist.push(item) - ) + // courseslist.push(item) + arr.push(item) + courseslist=arr } } }) + console.log(courseslist) + + + } + if(courseslist.length!=0){ + this.props.getMenuItemsindex(keys,courseslist[0].course_status.status) } + } + this.setState({ courseslist:courseslist, MenuItemskey:keys, @@ -156,7 +170,8 @@ class DetailTop extends Component{ Modalstype:false, Modalsbottomval:'', loadtype:false, - deletepathtype:false + deletepathtype:false, + putappointmenttype:false }) } @@ -219,6 +234,8 @@ class DetailTop extends Component{ ) } }) + + this.props.getMenuItemsindex(keys,courseslist[0].course_status.status) this.setState({ MenuItemskey:keys, courseslist:courseslist, @@ -245,6 +262,32 @@ class DetailTop extends Component{ pathcousestypeid:typeid }) } + + putappointment=()=>{ + if(this.props.checkIfLogin()===false){ + this.props.showLoginDialog() + return + } + + if(this.props.current_user&&this.props.current_user.profile_completed===false){ + this.setState({ + AccountProfiletype:true + }) + return + } + + this.setState({ + Modalstype:true, + Modalstopval:"是否确认立即预约?", + Modalsbottomval:"", + cardsModalcancel:()=>this.cardsModalcancel(), + putappointmenttype:true, + loadtype:false + }) + } + + + ysljoinmodalCancel=()=>{ this.setState({ yslJointhe:false @@ -267,9 +310,40 @@ class DetailTop extends Component{ OpenCourseTypes:false }) } + + getappointment=()=>{ + let pathid=this.props.match.params.pathId; + let url=`/paths/${pathid}/appointment.json` + axios.post(url).then((response) => { + + if (response.status === 200) { + + if(response.data.status===0){ + this.setState({ + getappointmenttype:true + }) + this.cardsModalcancel() + // this.props.getlistdatas() + this.props.showNotification(response.data.message) + }else{ + this.props.showNotification(response.data.message) + } + + } + }).catch((error) => { + console.log(error) + this.cardsModalcancel() + }) + } + + hideAccountProfile=()=>{ + this.setState({ + AccountProfiletype:false + }) + } render(){ let{detailInfoList}=this.props; - let{Modalstype,Modalstopval,cardsModalcancel,OpenCourseTypes,Modalsbottomval,cardsModalsavetype,loadtype}=this.state; + let{Modalstype,Modalstopval,cardsModalcancel,putappointmenttype,Modalsbottomval,cardsModalsavetype,loadtype,getappointmenttype,AccountProfiletype}=this.state; const radioStyle = { display: 'block', height: '30px', @@ -292,24 +366,48 @@ class DetailTop extends Component{ + let applypath=this.props.detailInfoList&&this.props.detailInfoList.participant_count!=undefined&&this.props.detailInfoList&&this.props.detailInfoList.allow_statistics===false; + let coursestypes=this.props.courses!=undefined&&this.props.courses.length===0; + let isadminallow_statistics=this.props.courses&&this.props.courses.length===0&&this.props.detailInfoList&&this.props.detailInfoList.allow_statistics===true; + return( -
                  +
                  40?"subhead mb100":"subhead mb70":this.state.MenuItemskey===this.props.courses.length?"subhead mb120":detailInfoList.name.length>40?"subhead mb100":"subhead mb80"}> + {AccountProfiletype===true?this.hideAccountProfile()} + {...this.props} + {...this.state} + />:""} + this.reovkissuePaths():putappointmenttype===true?()=>this.getappointment():()=>this.cardsModalsave()} loadtype={loadtype} > {this.state.yslJointhe===true?this.ysljoinmodalCancel()} ysljoinmodalCanceltwo={()=>this.ysljoinmodalCanceltwo(this.state.MenuItemskey)}>:""} {this.state.OpenCourseTypes===true?this.OpenCourseCancel()}/>:""} + { detailInfoList && -
                  +
                  {/*27?detailInfoList.name:""}>*/} @@ -428,9 +526,7 @@ class DetailTop extends Component{
                  - {this.props.courses===undefined||this.props.courses.length===0?"":
                  - -
                • + {this.props.courses===undefined||isadminallow_statistics===true?"":
                  + {this.props.courses===undefined||this.props.courses.length===0?"":
                • - - {this.props.courses===undefined?"":this.state.courseslist.map((item,key)=>{ - if(item.course_identity<4){ - return( - - - - - - )}}) - } + {this.state.courseslist.map((item,key)=>{ + if(item.course_identity<4){ + return( + + + + + + )}}) + } - - - 第 {this.state.MenuItemskey} 次开课 - - -
                • - -
                • - {this.state.courseslist.map((item,key)=>{ - return( -
                  + } + + {this.props.courses===undefined||this.props.courses.length===0?"":
                • + {this.state.courseslist.map((item,key)=>{ + return( +
                  @@ -512,7 +608,7 @@ class DetailTop extends Component{
                  - +
                  结课时间: @@ -524,7 +620,7 @@ class DetailTop extends Component{
                  - +
                  报名人数: @@ -534,17 +630,15 @@ class DetailTop extends Component{
                  -
                  - ) - }) - } - -
                • +
                  + ) + }) + } -
                • - - {this.state.courseslist.map((item,key)=>{ + } + + {this.props.courses===undefined||this.props.courses.length===0?"":
                • + + + {/* + height: 158px; + }*/} + {this.state.courseslist.map((item,key)=>{ + + return( +
                  + {applypath===false?"":this.state.MenuItemskey===this.props.courses.length||coursestypes===true? + this.props.detailInfoList&&this.props.detailInfoList.has_participate===false? + getappointmenttype===true?预约报名成功:this.putappointment()}>期待开课并预约报名: + 预约报名成功:""} + + {/*{item.course_status.status===0?
                  即将开课
                  :""}*/} + {item.course_status.status===1?
                  {item.course_status.time}
                  :""} + {item.course_status.status===2&&item.course_identity<6?
                  已结束
                  :""} + {/*
                  已结束
                  */} + {item.course_status.status===0? + item.course_identity<5? + 进入课堂 + :item.course_identity<6?
                  报名成功
                  + :this.JoinnowCourse(item.course_id)}>立即报名:""} + + {item.course_status.status===1? + item.course_identity<5? + 进入课堂 + :item.course_identity<6? + 立即学习 + :this.JoinnowCourse(item.course_id,item.course_status.status)}>立即加入:""} + + {item.course_status.status===2? + item.course_identity<6? + 进入课堂 + :
                  已结束
                  :""} + +
                  + )})} + + +
                • } + + + + {applypath===false?"":this.state.MenuItemskey===this.props.courses.length?
                  :""} + + {applypath===false?"":this.props.courses.length===0?"":this.state.MenuItemskey===this.props.courses.length||coursestypes===true? + 当前预约报名人数:{getappointmenttype===true?this.props.detailInfoList&&this.props.detailInfoList.participant_count+1:this.props.detailInfoList&&this.props.detailInfoList.participant_count} + 当预约报名人数达到 {this.props.detailInfoList&&this.props.detailInfoList.student_count} 人时即将开课 + {/*{this.props.detailInfoList&&this.props.detailInfoList.has_participate===false?*/} + {/*getappointmenttype===true?预约报名成功:this.putappointment()}>期待开课并预约报名:*/} + {/*预约报名成功}*/} + + :""} + + {applypath===true&&this.props.courses.length===0?this.state.MenuItemskey===this.props.courses.length||coursestypes===true? + 当前预约报名人数:{getappointmenttype===true?this.props.detailInfoList&&this.props.detailInfoList.participant_count+1:this.props.detailInfoList&&this.props.detailInfoList.participant_count} + 当预约报名人数达到 {this.props.detailInfoList&&this.props.detailInfoList.student_count} 人时即将开课 + {this.props.detailInfoList&&this.props.detailInfoList.has_participate===false? + getappointmenttype===true?预约报名成功:this.putappointment()}>期待开课并预约报名: + 预约报名成功} + :"":""} + - return( -
                  - {item.course_status.status===0?
                  即将开课
                  :""} - {item.course_status.status===1?
                  {item.course_status.time}
                  :""} - {item.course_status.status===2&&item.course_identity<6?
                  已结束
                  :""} - - {item.course_status.status===0? - item.course_identity<5? - 进入课堂 - :item.course_identity<6?
                  报名成功
                  - :this.JoinnowCourse(item.course_id)}>立即报名:""} - - {item.course_status.status===1? - item.course_identity<5? - 进入课堂 - :item.course_identity<6? - 立即学习 - :this.JoinnowCourse(item.course_id,item.course_status.status)}>立即加入:""} - - {item.course_status.status===2? - item.course_identity<6? - 进入课堂 - :
                  已结束
                  :""} - -
                  - )})} - - -
                  }
                  diff --git a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js index f1b0a3bbb..b0f64abde 100644 --- a/public/react/src/modules/paths/PathDetail/PathDetailIndex.js +++ b/public/react/src/modules/paths/PathDetail/PathDetailIndex.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import {getImageUrl,markdownToHTML} from 'educoder'; +import {getImageUrl,markdownToHTML, configShareForCustom} from 'educoder'; import DetailTop from './DetailTop.js'; import DetailCards from './DetailCards.js' import AddCollaborators from "./addCollaborators.js"; @@ -14,24 +14,24 @@ import TPMRightSection from "../../tpm/component/TPMRightSection"; import styled from "styled-components"; const getItemStyle = (isDragging, draggableStyle) => ({ - // change background colour if dragging - background: isDragging ? '#dceeff' : '', - // styles we need to apply on draggables - ...draggableStyle, + // change background colour if dragging + background: isDragging ? '#dceeff' : '', + // styles we need to apply on draggables + ...draggableStyle, }); const getItems = count => - Array.from({ length: count }, (v, k) => k).map(k => ({ - id: `item-${k}`, - content: `item ${k}` - })); + Array.from({ length: count }, (v, k) => k).map(k => ({ + id: `item-${k}`, + content: `item ${k}` + })); // a little function to help us with reordering the result const reorder = (list, startIndex, endIndex) => { - const result = Array.from(list); - const [removed] = result.splice(startIndex, 1); - result.splice(endIndex, 0, removed); + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); - return result; + return result; }; const List = styled.div` @@ -66,94 +66,148 @@ const DragHandle = styled.div` `; const $ =window.$ class PathDetailIndex extends Component{ - constructor(props){ - super(props) - this.state={ + constructor(props){ + super(props) + this.state={ progress:undefined, tags:undefined, members:undefined, - detailInfoList:undefined, - clickdetailInfoListtype:false, - Modalstype:false, - Modalstopval:undefined, - Modalsbottomval:undefined, - cardsModalcancel:this.cardsModalcancel, - cardsModalsave:this.cardsModalsave, - user_id:undefined, - loadtype:false, + detailInfoList:undefined, + clickdetailInfoListtype:false, + Modalstype:false, + Modalstopval:undefined, + Modalsbottomval:undefined, + cardsModalcancel:this.cardsModalcancel, + cardsModalsave:this.cardsModalsave, + user_id:undefined, + loadtype:false, courses:undefined, - items: getItems(10), - pathtopskey:1 - } - this.onDragEnd = this.onDragEnd.bind(this); + items: getItems(10), + pathtopskey:1, + dataquerys:{}, + MenuItemsindex:1, + MenuItemsindextype:0 + } + this.onDragEnd = this.onDragEnd.bind(this); - } - onDragEnd(result) { - // dropped outside the list - if (!result.destination) { - return; - } + } + onDragEnd(result) { + // dropped outside the list + if (!result.destination) { + return; + } - try { + try { - }catch (e) { + }catch (e) { - } - const items = reorder( - this.state.members, - result.source.index, - result.destination.index - ); + } + const items = reorder( + this.state.members, + result.source.index, + result.destination.index + ); - this.setState({ - detailInfoList:this.state.detailInfoList, + this.setState({ + detailInfoList:this.state.detailInfoList, members:items, - items - }); - console.log(this.state.members) - console.log("items 数组数组数组数组") - console.log(items) - } - cardsModalcancel=()=>{ - this.setState({ - Modalstype:false, - }) - // TODO 这个是临时处理,还需要优化,这里要看怎么区分处理 - if (this.state.Modalstopval == '你确定要删除该成员吗?') { - return; - } + items + }); + console.log(this.state.members) + console.log("items 数组数组数组数组") + console.log(items) + } + cardsModalcancel=()=>{ + this.setState({ + Modalstype:false, + }) + // TODO 这个是临时处理,还需要优化,这里要看怎么区分处理 + if (this.state.Modalstopval == '你确定要删除该成员吗?') { + return; + } this.props.history.goBack() - } + } - cardsModalsave=()=>{ - this.setState({ - Modalstype:false, - }) + cardsModalsave=()=>{ + this.setState({ + Modalstype:false, + }) this.props.history.goBack() - } - // 加载markdown - updatamakedown=(id)=>{ - setTimeout(()=>{ - var shixunDescr = window.editormd.markdownToHTML(id, { - htmlDecode: "style,script,iframe", - taskList: true, - tex: true, - flowChart: true, - sequenceDiagram: true - }); - $("#"+id+" p:first").addClass("ReactMarkdown"); - }, 200) - } + } + // 加载markdown + updatamakedown=(id)=>{ + setTimeout(()=>{ + var shixunDescr = window.editormd.markdownToHTML(id, { + htmlDecode: "style,script,iframe", + taskList: true, + tex: true, + flowChart: true, + sequenceDiagram: true + }); + $("#"+id+" p:first").addClass("ReactMarkdown"); + }, 200) + } - componentDidMount(){ - this.getdatasindex() - } + componentDidMount(){ + this.getlistdatas() + } - getdatasindex=(key)=>{ + getlistdatas=()=>{ + const query = this.props.location.search; + // const type = query.split('?chinaoocTimestamp='); + // console.log("Eduinforms12345"); + // console.log(this.foo(query)); + // console.log(JSON.stringify(this.foo(query))); + var dataqueryss={} + try { + var foqus=this.foo(query); + if(JSON.stringify(foqus) ==="{}"){ + this.setState({ + dataquerys:{}, + }); + }else{ + this.setState({ + dataquerys:foqus, + }); + dataqueryss=foqus; + } + }catch (e) { + this.setState({ + dataquerys:{}, + }) + } + + this.getdatasindexs(undefined,dataqueryss); + } + //截取url 数据的 + foo=(url)=> { + var json = {}; + var regExp = /[\?\&](\w+)(=?)(\w*)/g; + var arr; + do { + arr = regExp.exec(url); + // console.log(arr); // arr = [完整的字符串, key, 等号或'', value或''] + + if (arr) { + var key = arr[1]; + var value = arr[3]; + // arr[2] === ''时, value = undefined + if (!arr[2]) + value = undefined; + + json[key] = value; + } + } while (arr); + return json; + } + getdatasindexs=(key,yslwebobject)=>{ + // yslwebobject 后端需要的接口 let pathid=this.props.match.params.pathId; let url="/paths/"+pathid+".json"; - axios.get(url).then((result)=>{ + axios.get(url, + {params:yslwebobject} + ).then((result)=>{ if (result.data.status === 407 || result.data.status === 401) { debugger return; @@ -164,11 +218,12 @@ class PathDetailIndex extends Component{ // window.location.href = "/403"; return; } + configShareForCustom(result.data.name, result.data.description) if(result.data.allow_visit===true){ this.setState({ detailInfoList:result.data, - courses:result.data.courses, + courses:result.data.courses, pathtopskey:key===undefined?1:key, // items: getItems(result.data.members.length), }) @@ -203,368 +258,448 @@ class PathDetailIndex extends Component{ }).catch((error)=>{ console.log(error); }) + }; + getMenuItemsindex=(key,status)=>{ + + this.setState({ + MenuItemsindex:key, + MenuItemsindextype:status + }) } + getdatasindex=(key)=>{ + // yslwebobject 后端需要的接口 + let pathid=this.props.match.params.pathId; + let url="/paths/"+pathid+".json"; + axios.get(url, + {params:this.state.dataquerys} + ).then((result)=>{ + if (result.data.status === 407 || result.data.status === 401) { + debugger + return; + } - updatadetailInfoList=()=>{ - this.getdatasindex(); - } - - clickNewsubscript=(val)=>{ - if(val===0){ - this.setState({ - clickdetailInfoListtype:true - }) - }else{ - this.setState({ - clickdetailInfoListtype:false - }) - } + if (result.data.status === 403) { + debugger + // window.location.href = "/403"; + return; + } + configShareForCustom(result.data.name, result.data.description) - } + if(result.data.allow_visit===true){ + this.setState({ + detailInfoList:result.data, + courses:result.data.courses, + pathtopskey:key===undefined?1:key, + // items: getItems(result.data.members.length), + }) + } - timeStamp=(value)=>{ - var secondTime = parseInt(value);// 秒 - var minuteTime = 0;// 分 - var hourTime = 0;// 小时 - if(secondTime > 60) {//如果秒数大于60,将秒数转换成整数 - //获取分钟,除以60取整数,得到整数分钟 - minuteTime = parseInt(secondTime / 60); - //获取秒数,秒数取佘,得到整数秒数 - secondTime = parseInt(secondTime % 60); - //如果分钟大于60,将分钟转换成小时 - if(minuteTime > 60) { - //获取小时,获取分钟除以60,得到整数小时 - hourTime = parseInt(minuteTime / 60); - //获取小时后取佘的分,获取分钟除以60取佘的分 - minuteTime = parseInt(minuteTime % 60); - } - } - var result = "" + parseInt(secondTime) + "秒"; - - if(minuteTime > 0) { - result = "" + parseInt(minuteTime) + "分" + result; - } - if(hourTime > 0) { - result = "" + parseInt(hourTime) + "小时" + result; - } - return result; - } + }).catch((error)=>{ + console.log(error); + }); - shanchuallow=(id)=>{ - this.setState({ - user_id:id, - Modalstype:true, - Modalstopval:"你确定要删除该成员吗?", - cardsModalsave:this.delectshanchuallow, - loadtype:false - }) - } + let righturl="/paths/"+pathid+"/right_banner.json"; + axios.get(righturl).then((result)=>{ + if (result.data.status === 407 || result.data.status === 401) { + debugger + return; + } - delectshanchuallow=()=>{ - let{user_id}=this.state; - let pathid=this.props.match.params.pathId; - let url="/paths/"+pathid+"/delete_member.json"; - let param={user_id:user_id}; - axios.delete(url,{data:param}).then((response) => { - if(response.data.status===1){ - if (this.props.current_user.user_id == user_id) { - this.props.history.push('/paths') - return; - } - this.props.showNotification(response.data.message) - this.setState({ - Modalstype:false, - // Modalstopval:response.data.message, - loadtype:false, - // cardsModalsave:this.cardsModalsave, - }) - this.updatadetailInfoList(); - } - }).catch((error) => { - console.log(error) - }) - } + if (result.data.status === 403) { + debugger + // window.location.href = "/403"; + return; + } - //上移 - moveup=(data)=>{ - // console.log(data); - let pathid=this.props.match.params.pathId; - let url=`/paths/${pathid}/up_member_position.json`; - axios.post(url,{ - user_id:data.id - }).then((response) => { - if(response.status === 200){ - console.log("上移"); - // console.log(this.state.detailInfoList.members); - // console.log(response); - - this.setState({ - detailInfoList:this.state.detailInfoList, + this.setState({ + // detailInfoList:result.data, + tags:result.data.tags, + progress:result.data.progress, + members:result.data.members, + items: getItems(result.data.members.length), + }) + + }).catch((error)=>{ + console.log(error); + }) + } + + updatadetailInfoList=()=>{ + this.getdatasindex(); + } + + clickNewsubscript=(val)=>{ + if(val===0){ + this.setState({ + clickdetailInfoListtype:true + }) + }else{ + this.setState({ + clickdetailInfoListtype:false + }) + } + + } + + timeStamp=(value)=>{ + var secondTime = parseInt(value);// 秒 + var minuteTime = 0;// 分 + var hourTime = 0;// 小时 + if(secondTime > 60) {//如果秒数大于60,将秒数转换成整数 + //获取分钟,除以60取整数,得到整数分钟 + minuteTime = parseInt(secondTime / 60); + //获取秒数,秒数取佘,得到整数秒数 + secondTime = parseInt(secondTime % 60); + //如果分钟大于60,将分钟转换成小时 + if(minuteTime > 60) { + //获取小时,获取分钟除以60,得到整数小时 + hourTime = parseInt(minuteTime / 60); + //获取小时后取佘的分,获取分钟除以60取佘的分 + minuteTime = parseInt(minuteTime % 60); + } + } + var result = "" + parseInt(secondTime) + "秒"; + + if(minuteTime > 0) { + result = "" + parseInt(minuteTime) + "分" + result; + } + if(hourTime > 0) { + result = "" + parseInt(hourTime) + "小时" + result; + } + return result; + } + + + shanchuallow=(id)=>{ + this.setState({ + user_id:id, + Modalstype:true, + Modalstopval:"你确定要删除该成员吗?", + cardsModalsave:this.delectshanchuallow, + loadtype:false + }) + } + + delectshanchuallow=()=>{ + let{user_id}=this.state; + let pathid=this.props.match.params.pathId; + let url="/paths/"+pathid+"/delete_member.json"; + let param={user_id:user_id}; + axios.delete(url,{data:param}).then((response) => { + if(response.data.status===1){ + if (this.props.current_user.user_id == user_id) { + this.props.history.push('/paths') + return; + } + this.props.showNotification(response.data.message) + this.setState({ + Modalstype:false, + // Modalstopval:response.data.message, + loadtype:false, + // cardsModalsave:this.cardsModalsave, + }) + this.updatadetailInfoList(); + } + }).catch((error) => { + console.log(error) + }) + } + + //上移 + moveup=(data)=>{ + // console.log(data); + let pathid=this.props.match.params.pathId; + let url=`/paths/${pathid}/up_member_position.json`; + axios.post(url,{ + user_id:data.id + }).then((response) => { + if(response.status === 200){ + console.log("上移"); + // console.log(this.state.detailInfoList.members); + // console.log(response); + + this.setState({ + detailInfoList:this.state.detailInfoList, members:response.data.members - }); - // console.log(this.state.detailInfoList.members); + }); + // console.log(this.state.detailInfoList.members); - } + } - }).catch((error) => { - console.log(error) - }) - } + }).catch((error) => { + console.log(error) + }) + } - //下移 - movedown =(data) => { - // console.log(data); - let pathid=this.props.match.params.pathId; - let url=`/paths/${pathid}/down_member_position.json`; - axios.post(url,{ - user_id:data.id - }).then((response) => { - if( response.status === 200){ - console.log("下移"); - // console.log(this.state.detailInfoList.members); - // console.log(response); - this.setState({ - detailInfoList:this.state.detailInfoList, - members:response.data.members - }); - // console.log(this.state.detailInfoList.members); - } - - }).catch((error) => { - console.log(error) - }) - } - render(){ - - this.updatamakedown("shixuns_propaedeutics"); - this.updatamakedown("subject_learning_notes"); - let {detailInfoList, - clickdetailInfoListtype, - Modalstype, - Modalstopval, - Modalsbottomval, - cardsModalcancel, - cardsModalsave, - loadtype, + //下移 + movedown =(data) => { + // console.log(data); + let pathid=this.props.match.params.pathId; + let url=`/paths/${pathid}/down_member_position.json`; + axios.post(url,{ + user_id:data.id + }).then((response) => { + if( response.status === 200){ + console.log("下移"); + // console.log(this.state.detailInfoList.members); + // console.log(response); + this.setState({ + detailInfoList:this.state.detailInfoList, + members:response.data.members + }); + // console.log(this.state.detailInfoList.members); + } + + }).catch((error) => { + console.log(error) + }) + } + render(){ + + this.updatamakedown("shixuns_propaedeutics"); + this.updatamakedown("subject_learning_notes"); + let {detailInfoList, + clickdetailInfoListtype, + Modalstype, + Modalstopval, + Modalsbottomval, + cardsModalcancel, + cardsModalsave, + loadtype, progress, members, tags, courses, - } = this.state + MenuItemsindex, + MenuItemsindextype + } = this.state - return( -
                  + // console.log(MenuItemsindex) + // console.log(MenuItemsindextype===2&&detailInfoList&&detailInfoList.allow_statistics===false) + return( +
                  - - -
                  - this.getdatasindex(key)}> -
                  -
                  -
                  -

                  - 简介 - {/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/} - {/**/} - {/**/} - {/**/} - {/**/} - {/**/} - {/*:""*/} - {/*}*/} -

                  -
                  -
                  - {detailInfoList === undefined ? "" :detailInfoList.description===null?"": -
                  - } -
                  -
                  -
                  - - -
                  -
                  -
                  -

                  - 课程须知 - {/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/} - {/**/} - {/**/} - {/**/} - {/**/} - {/**/} - {/*:""*/} - {/*}*/} -

                  -
                  - {detailInfoList === undefined ? "" :detailInfoList.learning_notes===null?"": -
                  + + +
                  + this.getdatasindex(key)} getMenuItemsindex={(key,status)=>this.getMenuItemsindex(key,status)} getlistdatas={()=>this.getlistdatas()}> +
                  +
                  +
                  +

                  + 简介 + {/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/} + {/**/} + {/**/} + {/**/} + {/**/} + {/**/} + {/*:""*/} + {/*}*/} +

                  +
                  +
                  + {detailInfoList === undefined ? "" :detailInfoList.description===null?"": +
                  } -
                  -
                  - {tags === undefined ? "" :tags === null ? "": -
                  -

                  技能标签 {tags.length}

                  - -
                  -
                  - { - tags && tags.map((item,key)=>{ - return( - {item.tag_name} - ) - }) - } -
                  -
                  - - -
                  20&&clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 fr":"newsubscript mb9 color-grey-9 none"} - onClick={()=>this.clickNewsubscript(0)} - >... -
                  -
                  - - -
                  this.clickNewsubscript(1)}> -
                  -
                  - -
                  - } - { - this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" : -
                  -

                  - 我的进展 - - {progress.my_score} / {progress.all_score} - -

                  -

                  - 已学 {progress.learned}% - 学习耗时{this.timeStamp(progress.time)} -

                  -
                  -
                  - } - - { - members ===undefined ?"":members === null ?"": -
                  -

                  教学团队

                  - - { members===undefined? - members && members.map((item,key)=>{ - return( -
                  - - 头像 - - -
                  -

                  {item.name} - {/*{*/} - {/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/} - {/* this.shanchuallow(item.id)}>:""*/} - {/*}*/} -

                  -
                  -

                  {item.school}{item.identity}

                  -
                  -
                  -
                  - ) - }) - :detailInfoList===undefined?"":detailInfoList.allow_add_member===true? - members && members.map((item,key)=>{ - return( -
                  - - 头像 - - -
                  -

                  {item.name} - {/* 新增role 判断是否能删除 1 管理员 2 合作者 */} - - { - detailInfoList===undefined?"":detailInfoList.allow_add_member===true && item.role == 2? - this.shanchuallow(item.id)}>:"" - } -

                  -
                  -

                  {item.school}{item.identity}

                  -
                  - { - detailInfoList===undefined?"":detailInfoList.allow_add_member===true?
                  - {key!=0?:""} - {key+1== members.length?"":} -
                  - :"" - } - -
                  -
                  - ) - }) - : members && members.map((item,key)=>{ - return( -
                  - - 头像 - - -
                  -

                  {item.name} - {/*{*/} - {/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/} - {/* this.shanchuallow(item.id)}>:""*/} - {/*}*/} -

                  -
                  -

                  {item.school}{item.identity}

                  -
                  -
                  -
                  - ) - })} - -
                  - } - - - - -
                  -
                  -
                  - -
                  - ) - } +
                  +
                  +
                  + + +
                  +
                  +
                  +

                  + 课程须知 + {/*{detailInfoList===undefined?"":detailInfoList.allow_statistics===true?*/} + {/**/} + {/**/} + {/**/} + {/**/} + {/**/} + {/*:""*/} + {/*}*/} +

                  +
                  + {detailInfoList === undefined ? "" :detailInfoList.learning_notes===null?"": +
                  + } +
                  +
                  + {tags === undefined ? "" :tags === null ? "": +
                  +

                  技能标签 {tags.length}

                  + +
                  +
                  + { + tags && tags.map((item,key)=>{ + return( + {item.tag_name} + ) + }) + } +
                  +
                  + + +
                  20&&clickdetailInfoListtype===false?"newsubscript mb9 color-grey-9 fr":"newsubscript mb9 color-grey-9 none"} + onClick={()=>this.clickNewsubscript(0)} + >... +
                  +
                  + + +
                  this.clickNewsubscript(1)}> +
                  +
                  + +
                  + } + { + this.props.checkIfLogin()===false?"":progress === undefined ? "" : progress === null ? "" : +
                  +

                  + 关卡数 + + {progress.my_score} / {progress.all_score} + +

                  +

                  + 已学 {progress.learned}% + 学习耗时{this.timeStamp(progress.time)} +

                  +
                  + 注: “我的进展”以已发布的实训详情关卡数为准。 +
                  + } + + { + members ===undefined ?"":members === null ?"": +
                  +

                  教学团队

                  + + { members===undefined? + members && members.map((item,key)=>{ + return( +
                  + + 头像 + + +
                  +

                  {item.name} + {/*{*/} + {/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/} + {/* this.shanchuallow(item.id)}>:""*/} + {/*}*/} +

                  +
                  +

                  + {item.school} + {/*{item.identity}*/} +

                  +
                  +
                  +
                  + ) + }) + :detailInfoList===undefined?"":detailInfoList.allow_add_member===true? + members && members.map((item,key)=>{ + return( +
                  + + 头像 + + +
                  +

                  {item.name} + {/* 新增role 判断是否能删除 1 管理员 2 合作者 */} + + { + detailInfoList===undefined?"":detailInfoList.allow_add_member===true && item.role == 2? + this.shanchuallow(item.id)}>:"" + } +

                  +
                  +

                  {item.school} + {/*{item.identity}*/} +

                  +
                  + { + detailInfoList===undefined?"":detailInfoList.allow_add_member===true?
                  + {key!=0?:""} + {key+1== members.length?"":} +
                  + :"" + } + +
                  +
                  + ) + }) + : members && members.map((item,key)=>{ + return( +
                  + + 头像 + + +
                  +

                  {item.name} + {/*{*/} + {/* detailInfoList===undefined?"":detailInfoList.allow_add_member===true?*/} + {/* this.shanchuallow(item.id)}>:""*/} + {/*}*/} +

                  +
                  +

                  {item.school} + {/*{item.identity}*/} +

                  +
                  +
                  +
                  + ) + })} + +
                  + } + + + + +
                  +
                  +
                  + +
                  + ) + } } export default PathDetailIndex; \ No newline at end of file diff --git a/public/react/src/modules/paths/PathNew.js b/public/react/src/modules/paths/PathNew.js index 95e343b13..d9da9c0d4 100644 --- a/public/react/src/modules/paths/PathNew.js +++ b/public/react/src/modules/paths/PathNew.js @@ -1,7 +1,7 @@ import React,{ Component } from "react"; import {getUrl,markdownToHTML} from 'educoder'; -import {Input} from 'antd'; +import {Input,Button} from 'antd'; import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; import axios from 'axios'; @@ -48,6 +48,8 @@ function create_editorMD(id, width, high, placeholder, imageUrl,initValue, callb imageUploadURL: imageUrl,//url onload: function () { // this.previewing(); + var id = this.id; + var editorName = this; $("#" + id + " [type=\"latex\"]").bind("click", function () { editorName.cm.replaceSelection("```latex"); editorName.cm.replaceSelection("\n"); @@ -58,9 +60,9 @@ function create_editorMD(id, width, high, placeholder, imageUrl,initValue, callb }); $("#" + 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.setCursor(__Cursor.line, __Cursor.ch - 3); editorName.cm.focus(); }); $("[type=\"inline\"]").attr("title", "行内公式"); @@ -86,7 +88,8 @@ class PathNew extends Component{ pathName:"", description:"", point:"", - flag_name:true + flag_name:true, + bottonloading:false } } @@ -124,6 +127,9 @@ class PathNew extends Component{ return; } if (this.isEditPage == true) { + this.setState({ + bottonloading:true + }) let pathId = this.props.match.params.pathId; const editUrl = `/paths/${pathId}.json` @@ -135,11 +141,21 @@ class PathNew extends Component{ // console.log(response.data.subject_id); if (response.data.subject_id) { this.props.history.push(`/paths/${response.data.subject_id}`) - } + }else{ + this.setState({ + bottonloading:false + }) + } }).catch((error)=>{ console.log(error); + this.setState({ + bottonloading:false + }) }) } else { + this.setState({ + bottonloading:true + }) let url="/paths.json" axios.post(url,{ name:pathName, @@ -149,9 +165,16 @@ class PathNew extends Component{ // console.log(response.data.subject_id); if (response.data.subject_id) { this.props.history.push(`/paths/${response.data.subject_id}`) - } + }else{ + this.setState({ + bottonloading:false + }) + } }).catch((error)=>{ console.log(error); + this.setState({ + bottonloading:false + }) }) } @@ -267,7 +290,7 @@ class PathNew extends Component{
                  - 提交 + {this.isEditPage ? 取消 diff --git a/public/react/src/modules/paths/SchoolStatistics/FirstTab.js b/public/react/src/modules/paths/SchoolStatistics/FirstTab.js index 2dc7afda8..8783c522c 100644 --- a/public/react/src/modules/paths/SchoolStatistics/FirstTab.js +++ b/public/react/src/modules/paths/SchoolStatistics/FirstTab.js @@ -1,203 +1,212 @@ -import React,{ Component } from "react"; -import {Pagination} from 'antd'; -import axios from 'axios'; - - -const $ = window.$; -const echarts = require('echarts'); -function InitChapterUsageSituation(_data){ - var Color = ['#49A9EE', '#FFD86E', '#98D87D', '#8996E6','#F3857B', '#B97BF3','#4DE8B4','#f76d0c','#510cf7','#def70c','#3bf70c','#0cf7e1']; - - var option = { - title: { - show:false - }, - tooltip : { - trigger: 'item', - formatter: "{d}%" - }, - legend: { - //orient: 'vertical', - // top: 'middle', - bottom: 30, - //left: 20, - data:["第1章", "第2章", "第3章", "第4章", "第5章"], - selectedMode:false - }, - series : [{ - name: '使用情况', - type: 'pie', - radius : '50%', - center: ['50%', '40%'], - selectedMode: 'single', - label: { - normal: { - // {abg|} - // {a|{a}}\n - formatter: ' {b|{b}} ', - backgroundColor: '#eee', - borderColor: '#aaa', - borderWidth: 1, - borderRadius: 4, - rich: { - a: { - color: '#999', - lineHeight: 22, - align: 'center' - }, - hr: { - borderColor: '#aaa', - width: '100%', - borderWidth: 0.5, - height: 0 - }, - b: { - fontSize: 16, - lineHeight: 33 - }, - per: { - color: '#eee', - backgroundColor: '#334455', - padding: [2, 4], - borderRadius: 2 - } - - } - }, - - }, - data: _data, - // [{"value":19,"name":"\u7b2c1\u7ae0"},{"value":45,"name":"\u7b2c2\u7ae0"},{"value":16,"name":"\u7b2c3\u7ae0"},{"value":10,"name":"\u7b2c4\u7ae0"},{"value":10,"name":"\u7b2c5\u7ae0"}], - itemStyle: { - emphasis: { - shadowBlur: 10, - shadowOffsetX: 0, - shadowColor: 'rgba(0, 0, 0, 0.5)' - }, - normal:{ - show: true, - color: function(params) { - return Color[params.dataIndex] - } - } - } - }] - }; - - var myChart = echarts.init(document.getElementById('chapterUsageSituation')); - myChart.setOption(option); -} -class FirstTab extends Component{ - constructor(props){ - super(props); - this.state = { - page:1, - total:undefined - } - } - - onChange=(pageNumber)=>{ - this.setState({ - page:pageNumber - }) - this.getData(pageNumber); - } - - getData=(page)=>{ - var pathId = this.props.match.params.pathId; - - const url = `/paths/${pathId}/statistics.json?page=`+page; - axios.get(url, { - }) - .then((response) => { - // TODO 没用,404返回的error - if (response.data.status == 404) { - this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') - return - } - this.setState({ ...response.data }) - const _data = response.data.stage_info.map( (item, index) => { - return { - value: item.value, - name: item.stage_no - } - }) - InitChapterUsageSituation(_data); - - const { course_count, learn_count, school_total_count, subject_name, subject_id } = response.data - this.props.initBannerData({ - course_count, - learn_count, - school_total_count, - subject_name, - subject_id - }) - this.setState({ - total:response.data.school_total_count - }) - }) - .catch(function (error) { - console.log(error); - }); - } - - componentDidMount(){ - let {page}=this.state; - this.getData(page); - } - - render(){ - const { schools, stage_info,page,total } = this.state; - return( -
                  -
                  -
                  -

                  课堂使用概况共{total}条记录

                  -
                  -
                  - - - - - - - - {/* - course_count: 30 - homework_count: 117 - name: "国防科技大学" - student_count: 2700 - */} - - { - schools && schools.map( (school, index) => { - return ( - - - - - - - ) - }) - } - -
                  序号所属院校课堂学生选用实训
                  { index + 1 }{school.name}{school.course_count}{school.student_count}{school.homework_count}
                  -
                  -
                  - { - total > 10 && - - } -
                  -
                  -
                  -
                  -

                  章节使用情况

                  -
                  -
                  -
                  - ) - } -} +import React,{ Component } from "react"; +import {Pagination} from 'antd'; +import axios from 'axios'; + + +const $ = window.$; +const echarts = require('echarts'); +function InitChapterUsageSituation(_data){ + var myChart = echarts.init(document.getElementById('chapterUsageSituation')); + myChart.showLoading({ + text: "数据获取中", + effect: 'whirling' + }) + var Color = ['#49A9EE', '#FFD86E', '#98D87D', '#8996E6','#F3857B', '#B97BF3','#4DE8B4','#f76d0c','#510cf7','#def70c','#3bf70c','#0cf7e1']; + + var option = { + title: { + show:false + }, + tooltip : { + trigger: 'item', + formatter: "{d}%" + }, + legend: { + //orient: 'vertical', + // top: 'middle', + bottom: 30, + //left: 20, + data:["第1章", "第2章", "第3章", "第4章", "第5章"], + selectedMode:false + }, + series : [{ + name: '使用情况', + type: 'pie', + radius : '50%', + center: ['50%', '40%'], + selectedMode: 'single', + label: { + normal: { + // {abg|} + // {a|{a}}\n + formatter: ' {b|{b}} ', + backgroundColor: '#eee', + borderColor: '#aaa', + borderWidth: 1, + borderRadius: 4, + rich: { + a: { + color: '#999', + lineHeight: 22, + align: 'center' + }, + hr: { + borderColor: '#aaa', + width: '100%', + borderWidth: 0.5, + height: 0 + }, + b: { + fontSize: 16, + lineHeight: 33 + }, + per: { + color: '#eee', + backgroundColor: '#334455', + padding: [2, 4], + borderRadius: 2 + } + + } + }, + + }, + data: _data, + // [{"value":19,"name":"\u7b2c1\u7ae0"},{"value":45,"name":"\u7b2c2\u7ae0"},{"value":16,"name":"\u7b2c3\u7ae0"},{"value":10,"name":"\u7b2c4\u7ae0"},{"value":10,"name":"\u7b2c5\u7ae0"}], + itemStyle: { + emphasis: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: 'rgba(0, 0, 0, 0.5)' + }, + normal:{ + show: true, + color: function(params) { + return Color[params.dataIndex] + } + } + } + }] + }; + + + + setTimeout(() => { + myChart.setOption(option); + myChart.hideLoading(); + }, 1000) +} +class FirstTab extends Component{ + constructor(props){ + super(props); + this.state = { + page:1, + total:undefined + } + } + + onChange=(pageNumber)=>{ + this.setState({ + page:pageNumber + }) + this.getData(pageNumber); + } + + getData=(page)=>{ + var pathId = this.props.match.params.pathId; + + const url = `/paths/${pathId}/statistics.json?page=`+page; + axios.get(url, { + }) + .then((response) => { + // TODO 没用,404返回的error + if (response.data.status == 404) { + this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') + return + } + this.setState({ ...response.data }) + const _data = response.data.stage_info.map( (item, index) => { + return { + value: item.value, + name: item.stage_no + } + }) + InitChapterUsageSituation(_data); + + const { course_count, learn_count, school_total_count, subject_name, subject_id } = response.data + this.props.initBannerData({ + course_count, + learn_count, + school_total_count, + subject_name, + subject_id + }) + this.setState({ + total:response.data.school_total_count + }) + }) + .catch(function (error) { + console.log(error); + }); + } + + componentDidMount(){ + let {page}=this.state; + this.getData(page); + } + + render(){ + const { schools, stage_info,page,total } = this.state; + return( +
                  +
                  +
                  +

                  课堂使用概况共{total}条记录

                  +
                  + + + + + + + + + {/* + course_count: 30 + homework_count: 117 + name: "国防科技大学" + student_count: 2700 + */} + + { + schools && schools.map( (school, index) => { + return ( + + + + + + + ) + }) + } + +
                  序号所属院校课堂学生选用实训
                  { index + 1 }{school.name}{school.course_count}{school.student_count}{school.homework_count}
                  +
                  +
                  + { + total > 10 && + + } +
                  +
                  +
                  +
                  +

                  章节使用情况

                  +
                  +
                  +
                  + ) + } +} export default FirstTab; \ No newline at end of file diff --git a/public/react/src/modules/paths/SchoolStatistics/SecondTab.js b/public/react/src/modules/paths/SchoolStatistics/SecondTab.js index c58ac6f9b..8716a14d5 100644 --- a/public/react/src/modules/paths/SchoolStatistics/SecondTab.js +++ b/public/react/src/modules/paths/SchoolStatistics/SecondTab.js @@ -1,271 +1,291 @@ -import React,{ Component } from "react"; -import axios from 'axios'; - - -const $ = window.$; -const echarts = require('echarts'); -function InitShixunStudyStatistics(yAxisMonth_a, barData_a, mapByNumber, myChart){ - let yAxisMonth = yAxisMonth_a -// [ -// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", -// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", -// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"]; - let barData = barData_a -// [ -// 1164, 739, 784, 720, 726, 556, 381, 432, -// 1164, 739, 784, 720, 726, 556, 381, 432, -// 1164, 739, 784, 720, 726, 556, 381, 432, 239]; - -// let yAxisMonth = yAxisMonth_a; -// let barData = barData_a; - - let barDataTwo = []; - let coordData2 = []; - let coordData = []; - for (let i = 0; i < barData.length; i++) { - barDataTwo.push(Math.max.apply(Math, barData) + 5000); - coordData.push({ - "coord": [Number(barData[i]) - 1, i] - }); - coordData2.push({ - "coord": [Math.max.apply(Math, barData) + 5000, i] - }) - } - var option = { - backgroundColor: "#fff", - title: { - text: '' - }, - legend: null, - tooltip: { - trigger: 'axis', - axisPointer: { - type: 'none' - }, - formatter: function(params) { - return params[0].name + ":" + (mapByNumber[params[0].name] && mapByNumber[params[0].name].shixun_name) + "
                  " + '学习人数: ' + params[0].value; - } - }, - grid: { - containLabel: true, - left: "30px", - top: "0", - bottom:"10px" - }, - yAxis: [{ - data: yAxisMonth, - inverse: true, - axisLine: { - show: false - }, - axisTick: { - show: false - }, - axisLabel: { - margin: 10, - textStyle: { - fontSize: 12, - color: '#747A7F' - }, - formatter: function(value) { - return '{Sunny|' + value + '}'; - }, - rich: { - value: { - lineHeight: 20 - }, - Sunny: { - height: 25, - padding: [0, 8, 0, 8], - align: 'center', - backgroundColor: '#fff' - } - } - } - },{ - data: yAxisMonth, - inverse: true, - axisLine: { - show: false - }, - axisTick: { - show: false - }, - axisLabel: { - show: false - } - } - ], - xAxis: [{ - type: "value", - splitLine: { - show: false - }, - axisLabel: { - show: false - }, - axisTick: { - show: false - }, - axisLine: { - show: false - } - }, { - type: "value", - splitLine: { - show: false - }, - axisLabel: { - show: false - }, - axisTick: { - show: false - }, - axisLine: { - show: false - } - }], - series: [{ - z: 10, - xAxisIndex: 0, - yAxisIndex: 0, - name: '', - type: 'pictorialBar', - data: barData, - barCategoryGap: '90%', - label: { - normal: { - show: true, - position: 'inside', - textStyle: { - fontSize: 12, - color: '#666' - } - } - }, - symbolRepeat: false, - symbolSize: ['100%', 25], - symbolOffset: [-16.5, 0], - itemStyle: { - normal: { - color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ - offset: 0, - color: '#FFD86E' - }], false), - borderRadius:'10' - } - }, - symbolClip: true, - symbolPosition: 'end', - symbol: 'rect' - }] - }; - myChart.setOption(option); -} -class SecondTab extends Component{ - constructor(props){ - super(props); - this.state = { - - } - } - - componentDidMount(){ - var pathId = this.props.match.params.pathId; - - var myChart = echarts.init(document.getElementById('shixunStudyStatistics')); - myChart.showLoading({ - text: "数据获取中", - effect: 'whirling' - }) - const url = `/paths/${pathId}/shixun_report.json` - axios.get(url, { - }) - .then((response) => { - // TODO 没用,404返回的error - if (response.data.status == 404) { - this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') - return - } - - /** - let yAxisMonth = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"]; - let barData = [1164, 739, 784, 720, 726, 556, 381, 432, 239]; - - { - "number": "6-1", - "shixun_name": "网页抓取及信息提取", - "member_count": 0, - "school_count": 0 - } - */ - let yAxisMonth = [] - let barData = [] - let shixunList = [] - let mapByNumber = {} - const _data = response.data.shixun_lists.forEach( (ar, index) => { - ar.forEach( (item, itemIndex) => { - shixunList.push(item) - yAxisMonth.push(item.number) - barData.push(item.member_count) - mapByNumber[item.number] = item - }) - }) - this.setState({ shixunList }, () => { - InitShixunStudyStatistics(yAxisMonth, barData, mapByNumber, myChart); - myChart.hideLoading() - }) - - - }) - .catch(function (error) { - console.log(error); - }); - } - - render(){ - const { shixunList } = this.state; - return( -
                  -
                  -
                  -

                  实训使用详情

                  -
                  - - - - - - - - - - - - { - shixunList && shixunList.map( (shixun, index) => { - return ( - - - - - - ) - }) - } - - -
                  章节实训名称学习人数受用院校
                  {shixun.number}{shixun.shixun_name}{shixun.member_count}{shixun.school_count}
                  -
                  -
                  -
                  -
                  -

                  实训学习统计

                  -
                  -
                  -
                  - ) - } -} +import React,{ Component } from "react"; +import axios from 'axios'; + + +const $ = window.$; +const echarts = require('echarts'); +function InitShixunStudyStatistics(yAxisMonth_a, barData_a, mapByNumber, myChart){ + let yAxisMonth = yAxisMonth_a +// [ +// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", +// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", +// "1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"]; + let barData = barData_a +// [ +// 1164, 739, 784, 720, 726, 556, 381, 432, +// 1164, 739, 784, 720, 726, 556, 381, 432, +// 1164, 739, 784, 720, 726, 556, 381, 432, 239]; + +// let yAxisMonth = yAxisMonth_a; +// let barData = barData_a; + + let barDataTwo = []; + let coordData2 = []; + let coordData = []; + for (let i = 0; i < barData.length; i++) { + barDataTwo.push(Math.max.apply(Math, barData) + 5000); + coordData.push({ + "coord": [Number(barData[i]) - 1, i] + }); + coordData2.push({ + "coord": [Math.max.apply(Math, barData) + 5000, i] + }) + } + var option = { + backgroundColor: "#fff", + title: { + text: '' + }, + legend: null, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'none' + }, + formatter: function(params) { + return params[0].name + ":" + (mapByNumber[params[0].name] && mapByNumber[params[0].name].shixun_name) + "
                  " + '学习人数: ' + params[0].value; + } + }, + grid: { + containLabel: true, + left: "30px", + top: "0", + bottom:"10px" + }, + yAxis: [{ + data: yAxisMonth, + inverse: true, + axisLine: { + show: false + }, + axisTick: { + show: false + }, + axisLabel: { + margin: 10, + textStyle: { + fontSize: 12, + color: '#747A7F' + }, + formatter: function(value) { + return '{Sunny|' + value + '}'; + }, + rich: { + value: { + lineHeight: 20 + }, + Sunny: { + height: 25, + padding: [0, 8, 0, 8], + align: 'center', + backgroundColor: '#fff' + } + } + } + },{ + data: yAxisMonth, + inverse: true, + axisLine: { + show: false + }, + axisTick: { + show: false + }, + axisLabel: { + show: false + } + } + ], + xAxis: [{ + type: "value", + splitLine: { + show: false + }, + axisLabel: { + show: false + }, + axisTick: { + show: false + }, + axisLine: { + show: false + } + }, { + type: "value", + splitLine: { + show: false + }, + axisLabel: { + show: false + }, + axisTick: { + show: false + }, + axisLine: { + show: false + } + }], + series: [{ + z: 10, + xAxisIndex: 0, + yAxisIndex: 0, + name: '', + type: 'pictorialBar', + data: barData, + barCategoryGap: '90%', + label: { + normal: { + show: true, + position: 'inside', + textStyle: { + fontSize: 12, + color: '#666' + } + } + }, + symbolRepeat: false, + symbolSize: ['100%', 25], + symbolOffset: [-16.5, 0], + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: '#FFD86E' + }], false), + borderRadius:'10' + } + }, + symbolClip: true, + symbolPosition: 'end', + symbol: 'rect' + }] + }; + myChart.setOption(option); +} +class SecondTab extends Component{ + constructor(props){ + super(props); + this.state = { + } + } + + componentDidMount(){ + var pathId = this.props.match.params.pathId; + + var myCharts = echarts.init(document.getElementById('showloding')); + myCharts.showLoading({ + text: "数据获取中", + effect: 'whirling' + }) + const url = `/paths/${pathId}/shixun_report.json` + axios.get(url, { + }) + .then((response) => { + // TODO 没用,404返回的error + if (response.data.status == 404) { + this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') + return + } + + /** + let yAxisMonth = ["1-1", "1-2", "1-3", "1-4", "2-1", "2-2", "2-3", "3-1", "3-2"]; + let barData = [1164, 739, 784, 720, 726, 556, 381, 432, 239]; + + { + "number": "6-1", + "shixun_name": "网页抓取及信息提取", + "member_count": 0, + "school_count": 0 + } + */ + let yAxisMonth = [] + let barData = [] + let shixunList = [] + let mapByNumber = {} + const _data = response.data.shixun_lists.forEach( (ar, index) => { + ar.forEach( (item, itemIndex) => { + shixunList.push(item) + yAxisMonth.push(item.number) + barData.push(item.member_count) + mapByNumber[item.number] = item + }) + }) + + this.setState({ + shixunList + }) + var myChart = echarts.init(document.getElementById('shixunStudyStatistics')); + myChart.showLoading({ + text: "数据获取中", + effect: 'whirling' + }) + setTimeout(() => { + InitShixunStudyStatistics(yAxisMonth, barData, mapByNumber, myChart); + myCharts.hideLoading(); + myChart.hideLoading(); + }, 1000) + + }) + .catch(function (error) { + console.log(error); + }); + } + + render(){ + const { shixunList } = this.state; + return( +
                  +
                  +
                  +
                  实训使用详情
                  +
                  + + + + + + + + + + + + { + shixunList && shixunList.map( (shixun, index) => { + return ( + + + + + + ) + }) + } + + +
                  章节实训名称学习人数受用院校
                  {shixun.number}{shixun.shixun_name}{shixun.member_count}{shixun.school_count}
                  +
                  +
                  +
                  +
                  + +
                  实训学习统计
                  + {shixunList===undefined?
                  :""} + {shixunList===undefined?"":
                  } +
                  +
                  + ) + } +} export default SecondTab; \ No newline at end of file diff --git a/public/react/src/modules/paths/SchoolStatistics/ThirdTab.js b/public/react/src/modules/paths/SchoolStatistics/ThirdTab.js index 03ff221ad..f24acbaf2 100644 --- a/public/react/src/modules/paths/SchoolStatistics/ThirdTab.js +++ b/public/react/src/modules/paths/SchoolStatistics/ThirdTab.js @@ -1,247 +1,247 @@ -import React,{ Component } from "react"; -import axios from 'axios'; - -const $ = window.$ -const echarts = require('echarts'); -function InitCollegeStatistic(_data, myChart){ - var data = _data - var _yData = data.map( item => { - return item.name - }) -// [{name: "湖南科技大学潇湘学院", 已通关: 0, 未通关: 4, sum: 4},{name: "长沙理工大学", 已通关: 0, 未通关: 7, sum: 7},{name: "安徽大学", 已通关: 1, 未通关: 8, sum: 9},{name: "湘潭大学兴湘学院", 已通关: 12, 未通关: 0, sum: 12}, -// {name: "湖南师范大学", 已通关: 10, 未通关: 2, sum: 12},{name: "湖南软件职业学院", 已通关: 11, 未通关: 1, sum: 12},{name: "湖南科技大学", 已通关: 91, 未通关: 34, sum: 125},{name: "湘潭大学", 已通关: 110, 未通关: 45, sum: 155}, -// {name: "湖南工业大学", 已通关: 133, 未通关: 41, sum: 174},{name: "国防科技大学", 已通关: 853, 未通关: 23, sum: 876}]; - // <% @schools.each do |s| %> - // data.push({name: "<%= s['name'] %>", '已通关': <%= s['pass_count'] %>, '未通关': <%= s['unpass_count'] %>}); - // <% end %> - - // =================右边要放的字段名及颜色=========== - var items = [{ - key: '学习人数', color: "#29BD8B" - }, { - key: '已通关', color: "#FF954C" - }, { - key: '未通关', color: "#CBCBCB" - }] - - data.forEach((d) => { - var sum = 0 - items.forEach((i) => { - sum += (d[i.key] || 0) - }) - d.sum = sum; - }) - - // =========================排序================ - data.sort((a, b) => a.sum - b.sum) - - var yData = _yData.reverse(); - // ["湖南科技大学潇湘学院", "长沙理工大学", "安徽大学", "湖南软件职业学院", "湖南师范大学", "湘潭大学兴湘学院", "湖南科技大学", "湘潭大学", "湖南工业大学", "国防科技大学"] - - var itemSeries = items.map((d, i) => { - var values = data.map((p) => p[d.key]) - return { - type: 'bar', - name: d.key, - data: values, - stack: 'all', - xAxisIndex: 1, - yAxisIndex: 1, - label: { - normal: { - color:'#FFF', - // show: ( i == 1 ? true :false), - show: true, - position: 'inside' - } - }, - itemStyle: { - normal: { - color: d.color - } - } - } - }) - - var option = { - backgroundColor: '#fff', // 背景 - tooltip : { - trigger: 'axis', - axisPointer : { - type : '' - } - }, - legend: { - data: ['学习人数','已通关','未通关'], - textStyle: { - color: '#05101A' - }, - right:"20px", - selectedMode:false - }, - grid: [{ - right: '56%', - top: '20', - containLabel: true - }, { - left: '45%', - width:'100%', - top: '20', - containLabel: true - }], - xAxis: [{ - type: 'value', - inverse: true, - splitLine: { - show: false - }, - axisLine: { - show: false - }, - axisLabel: { - show: false - }, - axisTick: { - show: false - } - }, { - type: 'value', - gridIndex: 1, - splitLine: { - show: false - }, - axisLine: { - show: false - }, - axisLabel: { - show: false - }, - axisTick: { - show: false - } - }], - yAxis: [{ - type: 'category', - data: yData, - max:10, - axisLine: { - show: false - }, - axisLabel: { - show: false - }, - axisTick: { - show: false - } - }, { - type: 'category', - data: yData, - max:10, - gridIndex: 1, - axisLine: { - show: false - }, - axisTick: { - show: false - } - }], - series: [...itemSeries, - { - name: '总计', - type: 'bar', - data: data.map((d) => d.sum), - xAxisIndex: 1, - yAxisIndex: 1, - barCategoryGap:'40%', - stack: 'all', - label: { - normal: { - show: true, - position: 'inside', - color: '#666' - } - }, - itemStyle: { - normal: { - color: '#fff' - } - } - }, - // ===================左边=================== - { - type: 'bar', - data: data.map((d) => d.sum), - barCategoryGap:'40%', - label: { - normal: { - show: true, - position: 'left', - color: '#29BD8B' - } - }, - itemStyle: { - normal: { - color: '#29BD8B' - } - } - }] - } - myChart.setOption(option); -} -class ThirdTab extends Component{ - constructor(props){ - super(props); - } - - componentDidMount(){ - var pathId = this.props.match.params.pathId; - - var myChart = echarts.init(document.getElementById('collegeStatistic')); - myChart.showLoading({ - text: "数据获取中", - effect: 'whirling' - }) - - const url = `/paths/${pathId}/school_report.json` - axios.get(url, { - }) - .then((response) => { - // TODO 没用,404返回的error - if (response.data.status == 404) { - this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') - return - } - this.setState({ ...response.data }) - // name: "湖南科技大学潇湘学院", 已通关: 0, 未通关: 4, sum: 4 - /** - "name": "国防科技大学", - "student_count": 9269, - "pass_count": 6061, - "unpass_count": 3208 - */ - const _data = response.data.schools.map( (item, index) => { - return { - name: item.name, - sum: item.student_count, - 已通关: item.pass_count, - 未通关: item.unpass_count, - } - }) - InitCollegeStatistic(_data, myChart); - myChart.hideLoading() - }) - .catch(function (error) { - console.log(error); - }); - } - - render(){ - return( -
                  -

                  院校学习情况

                  -
                  -
                  - ) - } -} +import React,{ Component } from "react"; +import axios from 'axios'; + +const $ = window.$ +const echarts = require('echarts'); +function InitCollegeStatistic(_data, myChart){ + var data = _data + var _yData = data.map( item => { + return item.name + }) +// [{name: "湖南科技大学潇湘学院", 已通关: 0, 未通关: 4, sum: 4},{name: "长沙理工大学", 已通关: 0, 未通关: 7, sum: 7},{name: "安徽大学", 已通关: 1, 未通关: 8, sum: 9},{name: "湘潭大学兴湘学院", 已通关: 12, 未通关: 0, sum: 12}, +// {name: "湖南师范大学", 已通关: 10, 未通关: 2, sum: 12},{name: "湖南软件职业学院", 已通关: 11, 未通关: 1, sum: 12},{name: "湖南科技大学", 已通关: 91, 未通关: 34, sum: 125},{name: "湘潭大学", 已通关: 110, 未通关: 45, sum: 155}, +// {name: "湖南工业大学", 已通关: 133, 未通关: 41, sum: 174},{name: "国防科技大学", 已通关: 853, 未通关: 23, sum: 876}]; + // <% @schools.each do |s| %> + // data.push({name: "<%= s['name'] %>", '已通关': <%= s['pass_count'] %>, '未通关': <%= s['unpass_count'] %>}); + // <% end %> + + // =================右边要放的字段名及颜色=========== + var items = [{ + key: '学习人数', color: "#29BD8B" + }, { + key: '已通关', color: "#FF954C" + }, { + key: '未通关', color: "#CBCBCB" + }] + + data.forEach((d) => { + var sum = 0 + items.forEach((i) => { + sum += (d[i.key] || 0) + }) + d.sum = sum; + }) + + // =========================排序================ + data.sort((a, b) => a.sum - b.sum) + + var yData = _yData.reverse(); + // ["湖南科技大学潇湘学院", "长沙理工大学", "安徽大学", "湖南软件职业学院", "湖南师范大学", "湘潭大学兴湘学院", "湖南科技大学", "湘潭大学", "湖南工业大学", "国防科技大学"] + + var itemSeries = items.map((d, i) => { + var values = data.map((p) => p[d.key]) + return { + type: 'bar', + name: d.key, + data: values, + stack: 'all', + xAxisIndex: 1, + yAxisIndex: 1, + label: { + normal: { + color:'#FFF', + // show: ( i == 1 ? true :false), + show: true, + position: 'inside' + } + }, + itemStyle: { + normal: { + color: d.color + } + } + } + }) + + var option = { + backgroundColor: '#fff', // 背景 + tooltip : { + trigger: 'axis', + axisPointer : { + type : '' + } + }, + legend: { + data: ['学习人数','已通关','未通关'], + textStyle: { + color: '#05101A' + }, + right:"20px", + selectedMode:false + }, + grid: [{ + right: '56%', + top: '20', + containLabel: true + }, { + left: '45%', + width:'100%', + top: '20', + containLabel: true + }], + xAxis: [{ + type: 'value', + inverse: true, + splitLine: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show: false + }, + axisTick: { + show: false + } + }, { + type: 'value', + gridIndex: 1, + splitLine: { + show: false + }, + axisLine: { + show: false + }, + axisLabel: { + show: false + }, + axisTick: { + show: false + } + }], + yAxis: [{ + type: 'category', + data: yData, + max:10, + axisLine: { + show: false + }, + axisLabel: { + show: false + }, + axisTick: { + show: false + } + }, { + type: 'category', + data: yData, + max:10, + gridIndex: 1, + axisLine: { + show: false + }, + axisTick: { + show: false + } + }], + series: [...itemSeries, + { + name: '总计', + type: 'bar', + data: data.map((d) => d.sum), + xAxisIndex: 1, + yAxisIndex: 1, + barCategoryGap:'40%', + stack: 'all', + label: { + normal: { + show: true, + position: 'inside', + color: '#666' + } + }, + itemStyle: { + normal: { + color: '#fff' + } + } + }, + // ===================左边=================== + { + type: 'bar', + data: data.map((d) => d.sum), + barCategoryGap:'40%', + label: { + normal: { + show: true, + position: 'left', + color: '#29BD8B' + } + }, + itemStyle: { + normal: { + color: '#29BD8B' + } + } + }] + } + myChart.setOption(option); +} +class ThirdTab extends Component{ + constructor(props){ + super(props); + } + + componentDidMount(){ + var pathId = this.props.match.params.pathId; + + var myChart = echarts.init(document.getElementById('collegeStatistic')); + myChart.showLoading({ + text: "数据获取中", + effect: 'whirling' + }) + + const url = `/paths/${pathId}/school_report.json` + axios.get(url, { + }) + .then((response) => { + // TODO 没用,404返回的error + if (response.data.status == 404) { + this.props.showSnackbar('未找到对应数据,请查看地址是否正确。') + return + } + this.setState({ ...response.data }) + // name: "湖南科技大学潇湘学院", 已通关: 0, 未通关: 4, sum: 4 + /** + "name": "国防科技大学", + "student_count": 9269, + "pass_count": 6061, + "unpass_count": 3208 + */ + const _data = response.data.schools.map( (item, index) => { + return { + name: item.name, + sum: item.student_count, + 已通关: item.pass_count, + 未通关: item.unpass_count, + } + }) + InitCollegeStatistic(_data, myChart); + myChart.hideLoading() + }) + .catch(function (error) { + console.log(error); + }); + } + + render(){ + return( +
                  +
                  院校学习情况
                  +
                  +
                  + ) + } +} export default ThirdTab; \ No newline at end of file diff --git a/public/react/src/modules/paths/ShixunPathCard.js b/public/react/src/modules/paths/ShixunPathCard.js index 166c6415a..d919b1a6b 100644 --- a/public/react/src/modules/paths/ShixunPathCard.js +++ b/public/react/src/modules/paths/ShixunPathCard.js @@ -1,5 +1,5 @@ import React, { Component } from 'react'; -import {getImageUrl} from 'educoder'; +import {getImageUrl , setImagesUrl } from 'educoder'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import { Tooltip } from 'antd'; import axios from 'axios'; @@ -22,51 +22,49 @@ class ShixunPathCard extends Component{ pathList && pathList.map((item,key)=>{ return( -
                  - - { - item.tag_name === null ? "" : -
                  - {item.tag_name} - {/**/} -
                  - } - +
                  + {/* item.tag_name === null ? "" : +
                  + {item.tag_name} + +
                  */} { item.excellent === false ? "" : -
                  - 开放课程 -
                  +
                  + 开放课程 +
                  } -
                  + {/*

                  非试用内容,需要授权

                  -
                  - +
                  */} + + {/*target="_blank"*/} - 详情图片 + 详情图片 -
                  -

                  - {item.name} +

                  +

                  + {item.name} {/*target="_blank"*/}

                  -

                  +

                  - - {item.stages_count} - + {/* */} + {/* */} + 章节: {item.stages_count} + {/* */} {/**/} {/*{item.shixuns_count}*/} {/**/} - - - {item.members_count} - + {/* */} + {/* */} + 学习人数: {item.members_count} + {/* */}

                  diff --git a/public/react/src/modules/paths/ShixunPathSearch.js b/public/react/src/modules/paths/ShixunPathSearch.js index c0060a528..8323cd607 100644 --- a/public/react/src/modules/paths/ShixunPathSearch.js +++ b/public/react/src/modules/paths/ShixunPathSearch.js @@ -7,9 +7,6 @@ import Pagination from '@icedesign/base/lib/pagination'; import '@icedesign/base/lib/pagination/style.js'; import './ShixunPaths.css'; - -const Search = Input.Search; - class ShixunPathSearch extends Component{ constructor(props) { super(props) @@ -122,9 +119,10 @@ class ShixunPathSearch extends Component{ {this.state.updata===undefined?"":} -
                  -
                  -
                  +
                  +
                  +
                  +
                  • 0 ? "" : "active"}>this.changeSelect(null)}>全部
                  • { sortList && sortList.map((item,key)=>{ @@ -133,18 +131,18 @@ class ShixunPathSearch extends Component{ ) }) } -
                  +
              -
              +
              {/* this.changeStatus("publish_time")}>全部*/} {/* this.changeStatus("mine")}>我的*/} - this.changeStatus("updated_at")}>最新 - this.changeStatus("myshixun_count")}>最热 + this.changeStatus("updated_at")}>最新 + this.changeStatus("myshixun_count")}>最热 {/*
              */} {/*/!* diff --git a/public/react/src/modules/projectPackages/MDEditors.js b/public/react/src/modules/projectPackages/MDEditors.js index 2c11e0895..abd1d2da8 100644 --- a/public/react/src/modules/projectPackages/MDEditors.js +++ b/public/react/src/modules/projectPackages/MDEditors.js @@ -166,9 +166,9 @@ 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.setCursor(__Cursor.line, __Cursor.ch - 3); _editorName.cm.focus(); }); $("[type=\"inline\"]").attr("title", "行内公式"); diff --git a/public/react/src/modules/projectPackages/packageconcnet.css b/public/react/src/modules/projectPackages/packageconcnet.css index f7ee4cc06..22dd4ebc8 100644 --- a/public/react/src/modules/projectPackages/packageconcnet.css +++ b/public/react/src/modules/projectPackages/packageconcnet.css @@ -295,11 +295,11 @@ .topsj{ position: absolute; - top: -6px; + top: -3px; } .bottomsj{ position: absolute; - bottom: -6px; + bottom: -5px; } .touchSelect .ant-spin-dot-spin{ margin-top: 30% !important; diff --git a/public/react/src/modules/test/ShareTest.js b/public/react/src/modules/test/ShareTest.js index 293396109..c715f8910 100644 --- a/public/react/src/modules/test/ShareTest.js +++ b/public/react/src/modules/test/ShareTest.js @@ -11,7 +11,7 @@ if(window.wx) { title: ' title', // 分享标题 desc: 'hello world', // 分享描述 link: 'https://www.educoder.net', // 分享链接,该链接域名或路径必须与当前页面对应的公众号JS安全域名一致 - imgUrl: 'https://pre-newweb.educoder.net/images/educoder/headNavLogo.png', // 分享图标 + imgUrl: 'https://test-newweb.educoder.net/images/educoder/headNavLogo.png', // 分享图标 success: function () { // 设置成功 } diff --git a/public/react/src/modules/topic_bank/Topic_bank.js b/public/react/src/modules/topic_bank/Topic_bank.js new file mode 100644 index 000000000..a4bbc9dd7 --- /dev/null +++ b/public/react/src/modules/topic_bank/Topic_bank.js @@ -0,0 +1,51 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import Loading from '../../Loading' + +import Loadable from 'react-loadable'; +import { TPMIndexHOC } from '../tpm/TPMIndexHOC' +import { SnackbarHOC } from 'educoder' + + +const PackageIndex = Loadable({ + loader: () => import('../user/usersInfo/InfosTopics'), + loading: Loading, +}) + + +class Topic_bank extends Component { + constructor(props) { + super(props) + } + + componentDidMount(){ + } + + render() { + return ( +
              + + + () + } + > + + () + } + > + + +
              + ); + } +} + +export default SnackbarHOC() (TPMIndexHOC (Topic_bank)) ; \ No newline at end of file diff --git a/public/react/src/modules/tpm/NewFooter.js b/public/react/src/modules/tpm/NewFooter.js index a85b35ccf..be1a1ed29 100644 --- a/public/react/src/modules/tpm/NewFooter.js +++ b/public/react/src/modules/tpm/NewFooter.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import { Redirect } from 'react-router'; +import { Link } from 'react-router-dom'; import { getImageUrl, toPath } from 'educoder' import PropTypes from 'prop-types'; @@ -29,12 +30,12 @@ class NewFooter extends Component {
              */}
              diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index 509f18ffb..992c77fac 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -766,9 +766,9 @@ submittojoinclass=(value)=>{ />
            • 教学案例
            • -
            • - 众包创新 -
            • + {/*
            • */} + {/*众包创新*/} + {/*
            • */}
            • 交流问答
            • {
            • 我的实训项目
            • 我的实践课程
            • 我的开发项目
            • -
            • 我的众包
            • + {/*
            • 我的众包
            • */}
            • 客户管理
            • diff --git a/public/react/src/modules/tpm/TPMBanner.js b/public/react/src/modules/tpm/TPMBanner.js index 0009e1f98..7b094a642 100644 --- a/public/react/src/modules/tpm/TPMBanner.js +++ b/public/react/src/modules/tpm/TPMBanner.js @@ -6,7 +6,9 @@ import {BrowserRouter as Router, Route, Link, Switch} from "react-router-dom"; import PropTypes from 'prop-types'; -import {Modal,Input,Radio,Pagination,message,Spin,Icon,Tooltip} from 'antd'; +import { Rating ,Progress} from "@icedesign/base"; + +import {Modal,Input,Radio,Pagination,message,Spin,Icon,Tooltip,Rate} from 'antd'; import AccountProfile from"../user/AccountProfile"; @@ -16,17 +18,6 @@ import axios from 'axios' import Modals from '../modals/Modals'; -// import { Rating,Progress } from '@icedesign/base'; - -import Rating from '@icedesign/base/lib/rating'; - -import Progress from '@icedesign/base/lib/progress'; - -// 引入业务组件样式 -import '@icedesign/base/lib/rating/style.js'; - -import '@icedesign/base/lib/progress/style.js'; - import './shixuns/css/TPMBanner.css'; let $ = window.$; @@ -205,7 +196,7 @@ class TPMBanner extends Component { SenttotheSearch=(value)=>{ let id = this.props.match.params.shixunId; let url="/shixuns/" + id +"/search_user_courses.json?search="+value; - axios.get(url, { + axios.get(encodeURI(url), { params: { page:1, limit:10 @@ -578,6 +569,15 @@ class TPMBanner extends Component { }; const antIcon = ; + const MyRate = ({ defaultValue, ...rest }) => { + let myValue = defaultValue; + console.log(myValue-Math.floor(myValue)) + // if (myValue < Math.ceil(myValue)) { + // myValue = Math.floor(myValue) + 0.5; + // } + + return ; + }; return ( shixunsDetails===undefined?"": @@ -616,7 +616,22 @@ class TPMBanner extends Component {

              - "); + } + else + { + html += "
          • "; + } + + html += "
          • " + text + "
              "; + lastLevel = level; + } + + var tocContainer = container.find(".markdown-toc"); + + if ((tocContainer.length < 1 && container.attr("previewContainer") === "false")) + { + var tocHTML = "
              "; + + tocHTML = (tocDropdown) ? "
              " + tocHTML + "
              " : tocHTML; + + container.html(tocHTML); + + tocContainer = container.find(".markdown-toc"); + } + + if (tocDropdown) + { + tocContainer.wrap("

              "); + } + + tocContainer.html("
                ").children(".markdown-toc-list").html(html.replace(/\r?\n?\\<\/ul\>/g, "")); + + return tocContainer; + }; + + /** + * + * 生成TOC下拉菜单 + * Creating ToC dropdown menu + * + * @param {Object} container 插入TOC的容器jQuery对象元素 + * @param {String} tocTitle ToC title + * @returns {Object} return toc-menu object + */ + + editormd.tocDropdownMenu = function(container, tocTitle) { + + tocTitle = tocTitle || "Table of Contents"; + + var zindex = 400; + var tocMenus = container.find("." + this.classPrefix + "toc-menu"); + + tocMenus.each(function() { + var $this = $(this); + var toc = $this.children(".markdown-toc"); + var icon = ""; + var btn = "" + icon + tocTitle + ""; + var menu = toc.children("ul"); + var list = menu.find("li"); + + toc.append(btn); + + list.first().before("
              • " + tocTitle + " " + icon + "

              • "); + + $this.mouseover(function(){ + menu.show(); + + list.each(function(){ + var li = $(this); + var ul = li.children("ul"); + + if (ul.html() === "") + { + ul.remove(); + } + + if (ul.length > 0 && ul.html() !== "") + { + var firstA = li.children("a").first(); + + if (firstA.children(".fa").length < 1) + { + firstA.append( $(icon).css({ float:"right", paddingTop:"4px" }) ); + } + } + + li.mouseover(function(){ + ul.css("z-index", zindex).show(); + zindex += 1; + }).mouseleave(function(){ + ul.hide(); + }); + }); + }).mouseleave(function(){ + menu.hide(); + }); + }); + + return tocMenus; + }; + + /** + * 简单地过滤指定的HTML标签 + * Filter custom html tags + * + * @param {String} html 要过滤HTML + * @param {String} filters 要过滤的标签 + * @returns {String} html 返回过滤的HTML + */ + + editormd.filterHTMLTags = function(html, filters) { + + if (typeof html !== "string") { + html = new String(html); + } + + if (typeof filters !== "string") { + return html; + } + + var expression = filters.split("|"); + var filterTags = expression[0].split(","); + var attrs = expression[1]; + + for (var i = 0, len = filterTags.length; i < len; i++) + { + var tag = filterTags[i]; + + html = html.replace(new RegExp("\<\s*" + tag + "\s*([^\>]*)\>([^\>]*)\<\s*\/" + tag + "\s*\>", "igm"), ""); + } + + //return html; + + if (typeof attrs !== "undefined") + { + var htmlTagRegex = /\<(\w+)\s*([^\>]*)\>([^\>]*)\<\/(\w+)\>/ig; + + if (attrs === "*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + return "<" + $2 + ">" + $4 + ""; + }); + } + else if (attrs === "on*") + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4, $5) { + var el = $("<" + $2 + ">" + $4 + ""); + var _attrs = $($1)[0].attributes; + var $attrs = {}; + + $.each(_attrs, function(i, e) { + if (e.nodeName !== '"') $attrs[e.nodeName] = e.nodeValue; + }); + + $.each($attrs, function(i) { + if (i.indexOf("on") === 0) { + delete $attrs[i]; + } + }); + + el.attr($attrs); + + var text = (typeof el[1] !== "undefined") ? $(el[1]).text() : ""; + + return el[0].outerHTML + text; + }); + } + else + { + html = html.replace(htmlTagRegex, function($1, $2, $3, $4) { + var filterAttrs = attrs.split(","); + var el = $($1); + el.html($4); + + $.each(filterAttrs, function(i) { + el.attr(filterAttrs[i], null); + }); + + return el[0].outerHTML; + }); + } + } + + return html; + }; + + /** + * 将Markdown文档解析为HTML用于前台显示 + * Parse Markdown to HTML for Font-end preview. + * + * @param {String} id 用于显示HTML的对象ID + * @param {Object} [options={}] 配置选项,可选 + * @returns {Object} div 返回jQuery对象元素 + */ + + editormd.markdownToHTML = function(id, options) { + var defaults = { + gfm : true, + toc : true, + tocm : false, + tocStartLevel : 1, + tocTitle : "目录", + tocDropdown : false, + tocContainer : "", + markdown : "", + markdownSourceCode : false, + htmlDecode : false, + autoLoadKaTeX : true, + pageBreak : true, + atLink : true, // for @link + emailLink : true, // for mail address auto link + tex : false, + taskList : false, // Github Flavored Markdown task lists + emoji : false, + flowChart : false, + sequenceDiagram : false, + previewCodeHighlight : true + }; + + editormd.$marked = marked; + + var div = $("#" + id); + var settings = div.settings = $.extend(true, defaults, options || {}); + var saveTo = div.find("textarea"); + + if (saveTo.length < 1) + { + div.append(""); + saveTo = div.find("textarea"); + } + + var markdownDoc = (settings.markdown === "") ? saveTo.val() : settings.markdown; + var markdownToC = []; + + var rendererOptions = { + toc : settings.toc, + tocm : settings.tocm, + tocStartLevel : settings.tocStartLevel, + taskList : settings.taskList, + emoji : settings.emoji, + tex : settings.tex, + pageBreak : settings.pageBreak, + atLink : settings.atLink, // for @link + emailLink : settings.emailLink, // for mail address auto link + flowChart : settings.flowChart, + sequenceDiagram : settings.sequenceDiagram, + previewCodeHighlight : settings.previewCodeHighlight, + }; + + var markedOptions = { + renderer : editormd.markedRenderer(markdownToC, rendererOptions), + gfm : settings.gfm, + tables : true, + breaks : true, + pedantic : false, + sanitize : (settings.htmlDecode) ? false : true, // 是否忽略HTML标签,即是否开启HTML标签解析,为了安全性,默认不开启 + smartLists : true, + smartypants : true + }; + + markdownDoc = new String(markdownDoc); + + var markdownParsed = marked(markdownDoc, markedOptions); + + markdownParsed = editormd.filterHTMLTags(markdownParsed, settings.htmlDecode); + + if (settings.markdownSourceCode) { + saveTo.text(markdownDoc); + } else { + saveTo.remove(); + } + + div.addClass("markdown-body " + this.classPrefix + "html-preview").append(markdownParsed); + + var tocContainer = (settings.tocContainer !== "") ? $(settings.tocContainer) : div; + + if (settings.tocContainer !== "") + { + tocContainer.attr("previewContainer", false); + } + + if (settings.toc) + { + div.tocContainer = this.markdownToCRenderer(markdownToC, tocContainer, settings.tocDropdown, settings.tocStartLevel); + + if (settings.tocDropdown || div.find("." + this.classPrefix + "toc-menu").length > 0) + { + this.tocDropdownMenu(div, settings.tocTitle); + } + + if (settings.tocContainer !== "") + { + div.find(".editormd-toc-menu, .editormd-markdown-toc").remove(); + } + } + + if (settings.previewCodeHighlight) + { + div.find("pre").addClass("prettyprint linenums"); + prettyPrint(); + } + + if (!editormd.isIE8) + { + if (settings.flowChart) { + div.find(".flowchart").flowChart(); + } + + if (settings.sequenceDiagram) { + div.find(".sequence-diagram").sequenceDiagram({theme: "simple"}); + } + } + + if (settings.tex) + { + var katexHandle = function() { + div.find("." + editormd.classNames.tex).each(function(){ + var tex = $(this); + katex.render(tex.html().replace(/</g, "<").replace(/>/g, ">"), tex[0]); + tex.find(".katex").css("font-size", "1.6em"); + }); + }; + + if (settings.autoLoadKaTeX && !editormd.$katex && !editormd.kaTeXLoaded) + { + this.loadKaTeX(function() { + editormd.$katex = katex; + editormd.kaTeXLoaded = true; + katexHandle(); + }); + } + else + { + katexHandle(); + } + } + + div.getMarkdown = function() { + return saveTo.val(); + }; + + return div; + }; + + // Editor.md themes, change toolbar themes etc. + // added @1.5.0 + editormd.themes = ["default", "dark"]; + + // Preview area themes + // added @1.5.0 + editormd.previewThemes = ["default", "dark"]; + + // CodeMirror / editor area themes + // @1.5.0 rename -> editorThemes, old version -> themes + editormd.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" + ]; + + editormd.loadPlugins = {}; + + editormd.loadFiles = { + js : [], + css : [], + plugin : [] + }; + + /** + * 动态加载Editor.md插件,但不立即执行 + * Load editor.md plugins + * + * @param {String} fileName 插件文件路径 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadPlugin = function(fileName, callback, into) { + callback = callback || function() {}; + + this.loadScript(fileName, function() { + editormd.loadFiles.plugin.push(fileName); + callback(); + }, into); + }; + + /** + * 动态加载CSS文件的方法 + * Load css file method + * + * @param {String} fileName CSS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadCSS = function(fileName, callback, into) { + into = into || "head"; + callback = callback || function() {}; + + var css = document.createElement("link"); + css.type = "text/css"; + css.rel = "stylesheet"; + css.onload = css.onreadystatechange = function() { + editormd.loadFiles.css.push(fileName); + callback(); + }; + + css.href = fileName + ".css"; + + if(into === "head") { + document.getElementsByTagName("head")[0].appendChild(css); + } else { + document.body.appendChild(css); + } + }; + + editormd.isIE = (navigator.appName == "Microsoft Internet Explorer"); + editormd.isIE8 = (editormd.isIE && navigator.appVersion.match(/8./i) == "8."); + + /** + * 动态加载JS文件的方法 + * Load javascript file method + * + * @param {String} fileName JS文件名 + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + * @param {String} [into="head"] 嵌入页面的位置 + */ + + editormd.loadScript = function(fileName, callback, into) { + + into = into || "head"; + callback = callback || function() {}; + + var script = null; + script = document.createElement("script"); + script.id = fileName.replace(/[\./]+/g, "-"); + script.type = "text/javascript"; + script.src = fileName + ".js"; + + if (editormd.isIE8) + { + script.onreadystatechange = function() { + if(script.readyState) + { + if (script.readyState === "loaded" || script.readyState === "complete") + { + script.onreadystatechange = null; + editormd.loadFiles.js.push(fileName); + callback(); + } + } + }; + } + else + { + script.onload = function() { + editormd.loadFiles.js.push(fileName); + callback(); + }; + } + + if (into === "head") { + document.getElementsByTagName("head")[0].appendChild(script); + } else { + document.body.appendChild(script); + } + }; + + // 使用国外的CDN,加载速度有时会很慢,或者自定义URL + // You can custom KaTeX load url. + editormd.katexURL = { + css : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min", + js : "//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min" + }; + + editormd.kaTeXLoaded = false; + + /** + * 加载KaTeX文件 + * load KaTeX files + * + * @param {Function} [callback=function()] 加载成功后执行的回调函数 + */ + + editormd.loadKaTeX = function (callback) { + editormd.loadCSS(editormd.katexURL.css, function(){ + editormd.loadScript(editormd.katexURL.js, callback || function(){}); + }); + }; + + /** + * 锁屏 + * lock screen + * + * @param {Boolean} lock Boolean 布尔值,是否锁屏 + * @returns {void} + */ + + editormd.lockScreen = function(lock) { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + }; + + /** + * 动态创建对话框 + * Creating custom dialogs + * + * @param {Object} options 配置项键值对 Key/Value + * @returns {dialog} 返回创建的dialog的jQuery实例对象 + */ + + editormd.createDialog = function(options) { + var defaults = { + name : "", + width : 420, + height: 240, + title : "", + drag : true, + closed : true, + content : "", + mask : true, + maskStyle : { + backgroundColor : "#fff", + opacity : 0.1 + }, + lockScreen : true, + footer : true, + buttons : false + }; + + options = $.extend(true, defaults, options); + + var $this = this; + var editor = this.editor; + var classPrefix = editormd.classPrefix; + var guid = (new Date()).getTime(); + var dialogName = ( (options.name === "") ? classPrefix + "dialog-" + guid : options.name); + var mouseOrTouch = editormd.mouseOrTouch; + + var html = "
                "; + + if (options.title !== "") + { + html += "
                "; + html += "" + options.title + ""; + html += "
                "; + } + + if (options.closed) + { + html += ""; + } + + html += "
                " + options.content; + + if (options.footer || typeof options.footer === "string") + { + html += "
                " + ( (typeof options.footer === "boolean") ? "" : options.footer) + "
                "; + } + + html += "
                "; + + html += "
                "; + html += "
                "; + html += "
                "; + + editor.append(html); + + var dialog = editor.find("." + dialogName); + + dialog.lockScreen = function(lock) { + if (options.lockScreen) + { + $("html,body").css("overflow", (lock) ? "hidden" : ""); + $this.resize(); + } + + return dialog; + }; + + dialog.showMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").css(options.maskStyle).css("z-index", editormd.dialogZindex - 1).show(); + } + return dialog; + }; + + dialog.hideMask = function() { + if (options.mask) + { + editor.find("." + classPrefix + "mask").hide(); + } + + return dialog; + }; + + dialog.loading = function(show) { + var loading = dialog.find("." + classPrefix + "dialog-mask"); + loading[(show) ? "show" : "hide"](); + + return dialog; + }; + + dialog.lockScreen(true).showMask(); + + dialog.show().css({ + zIndex : editormd.dialogZindex, + border : (editormd.isIE8) ? "1px solid #ddd" : "", + width : (typeof options.width === "number") ? options.width + "px" : options.width, + height : (typeof options.height === "number") ? options.height + "px" : options.height + }); + + var dialogPosition = function(){ + dialog.css({ + top : ($(window).height() - dialog.height()) / 2 + "px", + left : ($(window).width() - dialog.width()) / 2 + "px" + }); + }; + + dialogPosition(); + + $(window).resize(dialogPosition); + + dialog.children("." + classPrefix + "dialog-close").bind(mouseOrTouch("click", "touchend"), function() { + dialog.hide().lockScreen(false).hideMask(); + }); + + if (typeof options.buttons === "object") + { + var footer = dialog.footer = dialog.find("." + classPrefix + "dialog-footer"); + + for (var key in options.buttons) + { + var btn = options.buttons[key]; + var btnClassName = classPrefix + key + "-btn"; + + footer.append(""); + btn[1] = $.proxy(btn[1], dialog); + footer.children("." + btnClassName).bind(mouseOrTouch("click", "touchend"), btn[1]); + } + } + + if (options.title !== "" && options.drag) + { + var posX, posY; + var dialogHeader = dialog.children("." + classPrefix + "dialog-header"); + + if (!options.mask) { + dialogHeader.bind(mouseOrTouch("click", "touchend"), function(){ + editormd.dialogZindex += 2; + dialog.css("z-index", editormd.dialogZindex); + }); + } + + dialogHeader.mousedown(function(e) { + e = e || window.event; //IE + posX = e.clientX - parseInt(dialog[0].style.left); + posY = e.clientY - parseInt(dialog[0].style.top); + + document.onmousemove = moveAction; + }); + + var userCanSelect = function (obj) { + obj.removeClass(classPrefix + "user-unselect").off("selectstart"); + }; + + var userUnselect = function (obj) { + obj.addClass(classPrefix + "user-unselect").on("selectstart", function(event) { // selectstart for IE + return false; + }); + }; + + var moveAction = function (e) { + e = e || window.event; //IE + + var left, top, nowLeft = parseInt(dialog[0].style.left), nowTop = parseInt(dialog[0].style.top); + + if( nowLeft >= 0 ) { + if( nowLeft + dialog.width() <= $(window).width()) { + left = e.clientX - posX; + } else { + left = $(window).width() - dialog.width(); + document.onmousemove = null; + } + } else { + left = 0; + document.onmousemove = null; + } + + if( nowTop >= 0 ) { + top = e.clientY - posY; + } else { + top = 0; + document.onmousemove = null; + } + + + document.onselectstart = function() { + return false; + }; + + userUnselect($("body")); + userUnselect(dialog); + dialog[0].style.left = left + "px"; + dialog[0].style.top = top + "px"; + }; + + document.onmouseup = function() { + userCanSelect($("body")); + userCanSelect(dialog); + + document.onselectstart = null; + document.onmousemove = null; + }; + + dialogHeader.touchDraggable = function() { + var offset = null; + var start = function(e) { + var orig = e.originalEvent; + var pos = $(this).parent().position(); + + offset = { + x : orig.changedTouches[0].pageX - pos.left, + y : orig.changedTouches[0].pageY - pos.top + }; + }; + + var move = function(e) { + e.preventDefault(); + var orig = e.originalEvent; + + $(this).parent().css({ + top : orig.changedTouches[0].pageY - offset.y, + left : orig.changedTouches[0].pageX - offset.x + }); + }; + + this.bind("touchstart", start).bind("touchmove", move); + }; + + dialogHeader.touchDraggable(); + } + + editormd.dialogZindex += 2; + + return dialog; + }; + + /** + * 鼠标和触摸事件的判断/选择方法 + * MouseEvent or TouchEvent type switch + * + * @param {String} [mouseEventType="click"] 供选择的鼠标事件 + * @param {String} [touchEventType="touchend"] 供选择的触摸事件 + * @returns {String} EventType 返回事件类型名称 + */ + + editormd.mouseOrTouch = function(mouseEventType, touchEventType) { + mouseEventType = mouseEventType || "click"; + touchEventType = touchEventType || "touchend"; + + var eventType = mouseEventType; + + try { + document.createEvent("TouchEvent"); + eventType = touchEventType; + } catch(e) {} + + return eventType; + }; + + /** + * 日期时间的格式化方法 + * Datetime format method + * + * @param {String} [format=""] 日期时间的格式,类似PHP的格式 + * @returns {String} datefmt 返回格式化后的日期时间字符串 + */ + + editormd.dateFormat = function(format) { + format = format || ""; + + var addZero = function(d) { + return (d < 10) ? "0" + d : d; + }; + + var date = new Date(); + var year = date.getFullYear(); + var year2 = year.toString().slice(2, 4); + var month = addZero(date.getMonth() + 1); + var day = addZero(date.getDate()); + var weekDay = date.getDay(); + var hour = addZero(date.getHours()); + var min = addZero(date.getMinutes()); + var second = addZero(date.getSeconds()); + var ms = addZero(date.getMilliseconds()); + var datefmt = ""; + + var ymd = year2 + "-" + month + "-" + day; + var fymd = year + "-" + month + "-" + day; + var hms = hour + ":" + min + ":" + second; + + switch (format) + { + case "UNIX Time" : + datefmt = date.getTime(); + break; + + case "UTC" : + datefmt = date.toUTCString(); + break; + + case "yy" : + datefmt = year2; + break; + + case "year" : + case "yyyy" : + datefmt = year; + break; + + case "month" : + case "mm" : + datefmt = month; + break; + + case "cn-week-day" : + case "cn-wd" : + var cnWeekDays = ["日", "一", "二", "三", "四", "五", "六"]; + datefmt = "星期" + cnWeekDays[weekDay]; + break; + + case "week-day" : + case "wd" : + var weekDays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]; + datefmt = weekDays[weekDay]; + break; + + case "day" : + case "dd" : + datefmt = day; + break; + + case "hour" : + case "hh" : + datefmt = hour; + break; + + case "min" : + case "ii" : + datefmt = min; + break; + + case "second" : + case "ss" : + datefmt = second; + break; + + case "ms" : + datefmt = ms; + break; + + case "yy-mm-dd" : + datefmt = ymd; + break; + + case "yyyy-mm-dd" : + datefmt = fymd; + break; + + case "yyyy-mm-dd h:i:s ms" : + case "full + ms" : + datefmt = fymd + " " + hms + " " + ms; + break; + + case "full" : + case "yyyy-mm-dd h:i:s" : + default: + datefmt = fymd + " " + hms; + break; + } + + return datefmt; + }; + + return editormd; + +})); diff --git a/vendor/assets/editormd/languages/en.js b/vendor/assets/editormd/languages/en.js new file mode 100755 index 000000000..0120a46e1 --- /dev/null +++ b/vendor/assets/editormd/languages/en.js @@ -0,0 +1,127 @@ +(function(){ + var factory = function (exports) { + var lang = { + name : "en", + description : "Open source online Markdown editor.", + tocTitle : "Table of Contents", + toolbar : { + undo : "Undo(Ctrl+Z)", + redo : "Redo(Ctrl+Y)", + bold : "Bold", + del : "Strikethrough", + italic : "Italic", + quote : "Block quote", + ucwords : "Words first letter convert to uppercase", + uppercase : "Selection text convert to uppercase", + lowercase : "Selection text convert to lowercase", + h1 : "Heading 1", + h2 : "Heading 2", + h3 : "Heading 3", + h4 : "Heading 4", + h5 : "Heading 5", + h6 : "Heading 6", + "list-ul" : "Unordered list", + "list-ol" : "Ordered list", + hr : "Horizontal rule", + link : "Link", + "reference-link" : "Reference link", + image : "Image", + code : "Code inline", + "preformatted-text" : "Preformatted text / Code block (Tab indent)", + "code-block" : "Code block (Multi-languages)", + table : "Tables", + datetime : "Datetime", + emoji : "Emoji", + "html-entities" : "HTML Entities", + pagebreak : "Page break", + watch : "Unwatch", + unwatch : "Watch", + preview : "HTML Preview (Press Shift + ESC exit)", + fullscreen : "Fullscreen (Press ESC exit)", + clear : "Clear", + search : "Search", + help : "Help", + info : "About " + exports.title + }, + buttons : { + enter : "Enter", + cancel : "Cancel", + close : "Close" + }, + dialog : { + link : { + title : "Link", + url : "Address", + urlTitle : "Title", + urlEmpty : "Error: Please fill in the link address." + }, + referenceLink : { + title : "Reference link", + name : "Name", + url : "Address", + urlId : "ID", + urlTitle : "Title", + nameEmpty: "Error: Reference name can't be empty.", + idEmpty : "Error: Please fill in reference link id.", + urlEmpty : "Error: Please fill in reference link url address." + }, + image : { + title : "Image", + url : "Address", + link : "Link", + alt : "Title", + uploadButton : "Upload", + imageURLEmpty : "Error: picture url address can't be empty.", + uploadFileEmpty : "Error: upload pictures cannot be empty!", + formatNotAllowed : "Error: only allows to upload pictures file, upload allowed image file format:" + }, + preformattedText : { + title : "Preformatted text / Codes", + emptyAlert : "Error: Please fill in the Preformatted text or content of the codes." + }, + codeBlock : { + title : "Code block", + selectLabel : "Languages: ", + selectDefaultText : "select a code language...", + otherLanguage : "Other languages", + unselectedLanguageAlert : "Error: Please select the code language.", + codeEmptyAlert : "Error: Please fill in the code content." + }, + htmlEntities : { + title : "HTML Entities" + }, + help : { + title : "Help" + } + } + }; + + exports.defaults.lang = lang; + }; + + // 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 + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); \ No newline at end of file diff --git a/vendor/assets/editormd/languages/zh-tw.js b/vendor/assets/editormd/languages/zh-tw.js new file mode 100755 index 000000000..c92d27111 --- /dev/null +++ b/vendor/assets/editormd/languages/zh-tw.js @@ -0,0 +1,127 @@ +(function(){ + var factory = function (exports) { + var lang = { + name : "zh-tw", + 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 : "插入分頁符", + watch : "關閉實時預覽", + unwatch : "開啟實時預覽", + preview : "全窗口預覽HTML(按 Shift + ESC 退出)", + fullscreen : "全屏(按 ESC 退出)", + clear : "清空", + search : "搜尋", + help : "使用幫助", + info : "關於" + exports.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 : "使用幫助" + } + } + }; + + exports.defaults.lang = lang; + }; + + // 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 + + define(["editormd"], function(editormd) { + factory(editormd); + }); + + } else { // for Sea.js + define(function(require) { + var editormd = require("../editormd"); + factory(editormd); + }); + } + } + else + { + factory(window.editormd); + } + +})(); \ No newline at end of file