From e15e24b36978beb01d0834b88a4a4d64cb42137e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com>
Date: Mon, 2 Sep 2019 13:48:35 +0800
Subject: [PATCH] =?UTF-8?q?=E5=90=88=E5=B9=B6=E9=98=BF=E9=87=8C=E4=BA=91?=
=?UTF-8?q?=E8=A7=A3=E5=86=B3=E7=9A=84=E9=97=AE=E9=A2=98?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app/assets/javascripts/admin.js | 26 +-
.../javascripts/admins/common-refuse-modal.js | 3 +-
.../javascripts/admins/dashboards/index.js | 66 +
.../javascripts/admins/departments/index.js | 173 +
.../admins/library_applies/index.js | 20 +
.../admins/mirror_repositories/edit.js | 19 +
.../admins/mirror_repositories/index.js | 4 +
.../javascripts/admins/mirror_scripts/form.js | 33 +
.../modals/admin-choose-mirror-modal.js | 32 +
.../modals/admin-edit-department-modal.js | 34 +
.../modals/admin-merge-department-modal.js | 110 +
.../modals/admin-replace-mirror-modal.js | 89 +
.../admins/modals/admin-upload-file-modal.js | 62 +
.../project_package_applies.js | 20 +
.../admins/shixun_settings/index.js | 44 +
.../javascripts/admins/shixuns/index.js | 14 +
.../javascripts/admins/video_applies/index.js | 20 +
app/assets/javascripts/college.js | 21 +
app/assets/javascripts/colleges/statistics.js | 156 +
app/assets/javascripts/homework_banks.js | 2 +
app/assets/stylesheets/admin.scss | 33 +-
app/assets/stylesheets/admins/common.scss | 4 +
app/assets/stylesheets/admins/dashboards.scss | 7 +
.../stylesheets/admins/departments.scss | 24 +
.../stylesheets/admins/library_applies.scss | 9 +
.../admins/project_package_apply.scss | 9 +
app/assets/stylesheets/admins/shixun.scss | 7 +
.../stylesheets/admins/shixun_settings.scss | 22 +
.../stylesheets/admins/video_apply.scss | 9 +
app/assets/stylesheets/college.scss | 13 +
.../stylesheets/colleges/statistic.scss | 135 +
app/assets/stylesheets/common.scss | 36 +
app/assets/stylesheets/homework_banks.scss | 3 +
.../stylesheets/select2-bootstrap4.min.scss | 2 +-
.../choose_mirror_repositories_controller.rb | 11 +
.../admins/dashboards_controller.rb | 47 +
.../admins/department_members_controller.rb | 20 +
.../admins/departments_controller.rb | 95 +
app/controllers/admins/files_controller.rb | 54 +
.../admins/library_applies_controller.rb | 25 +
.../admins/mirror_repositories_controller.rb | 97 +
.../admins/mirror_scripts_controller.rb | 59 +
.../admins/myshixuns_controller.rb | 14 +
.../project_package_applies_controller.rb | 37 +
.../admins/shixun_settings_controller.rb | 97 +
app/controllers/admins/shixuns_controller.rb | 64 +
.../admins/video_applies_controller.rb | 41 +
app/controllers/application_controller.rb | 6 +-
app/controllers/challenges_controller.rb | 23 +-
app/controllers/colleges_controller.rb | 171 +
.../concerns/admins/render_helper.rb | 48 +-
app/controllers/concerns/git_common.rb | 14 +-
app/controllers/courses_controller.rb | 224 +-
.../exercise_bank_questions_controller.rb | 418 +
app/controllers/exercise_banks_controller.rb | 129 +
.../exercise_questions_controller.rb | 18 +-
app/controllers/files_controller.rb | 23 +-
app/controllers/games_controller.rb | 53 -
.../graduation_works_controller.rb | 2 +-
app/controllers/gtopic_banks_controller.rb | 40 +
app/controllers/homework_banks_controller.rb | 69 +
.../poll_bank_questions_controller.rb | 158 +
app/controllers/polls_controller.rb | 6 +-
app/controllers/question_banks_controller.rb | 59 +-
app/controllers/shixuns_controller.rb | 23 +-
app/controllers/student_works_controller.rb | 20 +-
app/controllers/subjects_controller.rb | 4 +-
app/controllers/task_banks_controller.rb | 49 +
.../users/question_banks_controller.rb | 29 +-
.../admins/mirror_repositories_helper.rb | 23 +
app/helpers/exercise_bank_questions_helper.rb | 2 +
app/helpers/homework_banks_helper.rb | 2 +
app/helpers/homework_commons_helper.rb | 2 +-
app/helpers/shixuns_helper.rb | 13 +
app/jobs/delete_department_notify_job.rb | 21 +
app/models/challenge.rb | 8 +
app/models/customer.rb | 10 +
app/models/department.rb | 12 +
app/models/exercise_bank.rb | 3 +
app/models/exercise_bank_choice.rb | 3 +
app/models/exercise_bank_question.rb | 23 +-
app/models/exercise_bank_standard_answer.rb | 1 +
app/models/homework_common.rb | 2 +-
app/models/library_apply.rb | 4 +
app/models/mirror_operation_record.rb | 7 +
app/models/mirror_repository.rb | 4 +
app/models/myshixun.rb | 3 +
app/models/partner.rb | 2 +
app/models/partner_customer.rb | 4 +
app/models/school.rb | 3 +
app/models/shixun.rb | 27 +
app/models/student_work.rb | 1 +
app/models/user.rb | 2 +-
app/queries/admins/department_query.rb | 32 +
app/queries/admins/library_apply_query.rb | 29 +
app/queries/admins/myshixun_query.rb | 26 +
app/queries/admins/shixun_query.rb | 48 +
app/queries/admins/shixun_settings_query.rb | 54 +
app/queries/admins/user_query.rb | 8 +-
.../admins/add_department_member_service.rb | 20 +
.../admins/check_shixun_mirrors_service.rb | 89 +
app/services/admins/choose_mirror_service.rb | 21 +
.../admins/save_mirror_repository_service.rb | 37 +
app/services/homeworks_service.rb | 7 +-
app/services/users/question_bank_service.rb | 12 +-
app/templates/shared/main.css | 2 +-
.../shixun_work/shixun_work.html.erb | 10 +-
.../choose_mirror_repositories/create.js.erb | 5 +
.../choose_mirror_repositories/new.js.erb | 2 +
.../daily_school_statistics/index.html.erb | 2 +-
app/views/admins/dashboards/index.html.erb | 244 +-
.../admins/department_members/create.js.erb | 4 +
.../admins/department_members/destroy.js.erb | 2 +
app/views/admins/departments/edit.js.erb | 2 +
app/views/admins/departments/index.html.erb | 33 +
app/views/admins/departments/index.js.erb | 1 +
.../_add_department_member_modal.html.erb | 30 +
.../shared/_create_department_modal.html.erb | 35 +
.../shared/_department_item.html.erb | 34 +
.../shared/_edit_department_modal.html.erb | 25 +
.../admins/departments/shared/_list.html.erb | 28 +
.../departments/shared/_member_users.html.erb | 12 +
.../shared/_merge_department_modal.html.erb | 31 +
app/views/admins/departments/update.js.erb | 4 +
.../identity_authentications/index.html.erb | 2 +-
.../admins/library_applies/index.html.erb | 32 +
app/views/admins/library_applies/index.js.erb | 1 +
.../library_applies/shared/_list.html.erb | 56 +
.../admins/mirror_repositories/edit.html.erb | 8 +
.../admins/mirror_repositories/index.html.erb | 23 +
.../admins/mirror_repositories/index.js.erb | 1 +
.../admins/mirror_repositories/merge.js.erb | 5 +
.../admins/mirror_repositories/new.html.erb | 8 +
.../shared/_choose_mirror_modal.html.erb | 42 +
.../mirror_repositories/shared/_form.html.erb | 42 +
.../mirror_repositories/shared/_list.html.erb | 54 +
.../shared/_replace_mirror_modal.html.erb | 33 +
app/views/admins/mirror_scripts/edit.html.erb | 8 +
.../admins/mirror_scripts/index.html.erb | 14 +
app/views/admins/mirror_scripts/new.html.erb | 8 +
.../mirror_scripts/shared/_form.html.erb | 12 +
.../mirror_scripts/shared/_list.html.erb | 32 +
app/views/admins/myshixuns/index.html.erb | 14 +
app/views/admins/myshixuns/index.js.erb | 1 +
.../admins/myshixuns/shared/_list.html.erb | 49 +
.../index.html.erb | 2 +-
.../project_package_applies/index.html.erb | 32 +
.../project_package_applies/index.js.erb | 1 +
.../shared/_list.html.erb | 56 +
app/views/admins/shared/403.html.erb | 6 +
app/views/admins/shared/500.html.erb | 2 +-
.../_admin_common_refuse_modal.html.erb | 6 +-
app/views/admins/shared/_paginate.html.erb | 2 +-
app/views/admins/shared/_sidebar.html.erb | 23 +-
.../shared/modal/_upload_file_modal.html.erb | 32 +
.../shixun_authorizations/index.html.erb | 2 +-
.../admins/shixun_settings/index.html.erb | 76 +
app/views/admins/shixun_settings/index.js.erb | 1 +
.../shixun_settings/shared/_list.html.erb | 35 +
.../shixun_settings/shared/_td.html.erb | 51 +
.../admins/shixun_settings/update.js.erb | 1 +
app/views/admins/shixuns/index.html.erb | 32 +
app/views/admins/shixuns/index.js.erb | 1 +
.../admins/shixuns/shared/_list.html.erb | 55 +
.../subject_authorizations/index.html.erb | 2 +-
app/views/admins/users/edit.html.erb | 2 +-
app/views/admins/users/index.html.erb | 2 +-
app/views/admins/users/index.json.jbuilder | 6 +
.../users/shared/_reward_grade_modal.html.erb | 2 +-
app/views/admins/video_applies/index.html.erb | 32 +
app/views/admins/video_applies/index.js.erb | 1 +
.../video_applies/shared/_list.html.erb | 57 +
.../challenges/crud_answer.json.jbuilder | 2 +-
.../colleges/_course_statistics.html.erb | 45 +
app/views/colleges/_student_rank.html.erb | 23 +
app/views/colleges/_teacher_rank.html.erb | 21 +
app/views/colleges/course_statistics.js.erb | 1 +
app/views/colleges/shared/_navbar.html.erb | 21 +
app/views/colleges/statistics.html.erb | 164 +
app/views/colleges/student_shixun.js.erb | 1 +
app/views/colleges/teachers.js.erb | 1 +
.../courses/export_course_info.xlsx.axlsx | 29 +
.../export_member_act_score.xlsx.axlsx | 25 +
.../export_member_scores_excel.xlsx.axlsx | 38 -
.../_exercise_bank_questions.json.jbuilder | 72 +
.../choose_shixun.json.jbuilder | 17 +
.../commit_shixun.json.jbuilder | 10 +
app/views/exercise_banks/show.json.jbuilder | 51 +
.../_exercise_questions.json.jbuilder | 6 +-
app/views/exercises/index.json.jbuilder | 1 +
.../exercises/start_answer.json.jbuilder | 7 +-
app/views/games/picture_display.json.jbuilder | 2 +-
app/views/gtopic_banks/edit.json.jbuilder | 15 +
app/views/gtopic_banks/show.json.jbuilder | 6 +
app/views/homework_banks/show.json.jbuilder | 9 +
.../homework_commons/index.json.jbuilder | 1 +
app/views/layouts/admin.html.erb | 1 +
app/views/layouts/college.html.erb | 24 +
app/views/polls/commit_result.json.jbuilder | 2 +-
app/views/polls/index.json.jbuilder | 1 +
.../question_banks/my_courses.json.jbuilder | 4 +
app/views/shixuns/add_file.json.jbuilder | 1 +
.../adjust_review_score.json.jbuilder | 5 +-
.../shixun_work_report.json.jbuilder | 1 +
app/views/student_works/show.json.jbuilder | 3 +-
app/views/task_banks/show.json.jbuilder | 14 +
.../users/question_banks/index.json.jbuilder | 15 +-
config/admins/sidebar.yml | 2 +-
config/initializers/assets.rb | 4 +-
config/locales/library_applies/zh-CN.yml | 7 +
config/locales/zh-CN.yml | 15 +-
config/routes.rb | 106 +-
...222_add_update_user_id_to_student_works.rb | 6 +
...dd_is_ordered_to_exercise_bank_question.rb | 5 +
...829025855_migrate_gtopic_bank_is_public.rb | 5 +
...829084147_migrate_course_group_position.rb | 11 +
...4803_add_announcement_to_course_modules.rb | 10 +
.../20190830082934_add_tag_to_libraries.rb | 5 +
...190831014325_migrate_poll_bank_question.rb | 6 +
db/seeds.rb | 44 +-
lib/tasks/public_course_zhp.rake | 171 +
...fest-1c370772f16743f825981ab0e5c94237.json | 1 -
...fest-fd1f19755cf79ae07a20ee9d2676d85e.json | 1 +
...da5443521854cd6fe7eecf750cf443f1e699c9.css | 19193 +++
...443521854cd6fe7eecf750cf443f1e699c9.css.gz | Bin 0 -> 52434 bytes
...8bd28c4aff07b70bed9b41faf6899a89af4b57d.js | 28296 ----
...28c4aff07b70bed9b41faf6899a89af4b57d.js.gz | Bin 219374 -> 0 bytes
...ac4a62d8b76f65baf7b06fdedc47323635bcdaf.js | 129292 ++++++++++++++
...a62d8b76f65baf7b06fdedc47323635bcdaf.js.gz | Bin 0 -> 896729 bytes
...4cae77382331beba55b1570b3d3c8aa42442d5.css | 18405 --
...e77382331beba55b1570b3d3c8aa42442d5.css.gz | Bin 49605 -> 0 bytes
...5537a46deb578488e47bbb006d551b54f72895.css | 50125 ++++++
...7a46deb578488e47bbb006d551b54f72895.css.gz | Bin 0 -> 132235 bytes
...304541807c3ea985eb566bdabdbafee7f6c6735.js | 131164 +++++++++++++++
...541807c3ea985eb566bdabdbafee7f6c6735.js.gz | Bin 0 -> 935077 bytes
...c85a9ac11e536edc73fef6e7489723bf535e533.js | 29988 ----
...a9ac11e536edc73fef6e7489723bf535e533.js.gz | Bin 256348 -> 0 bytes
...c14745cec09853ea7d91c6fae856b96e788f46.css | 33017 ----
...745cec09853ea7d91c6fae856b96e788f46.css.gz | Bin 86666 -> 0 bytes
...2187815c096c25e0ab74aba341ae916166cd287.js | 109342 ++++++++++++
...7815c096c25e0ab74aba341ae916166cd287.js.gz | Bin 0 -> 711176 bytes
...4c4a620f522278a4668cc218465ad8f539966f.css | 15969 ++
...a620f522278a4668cc218465ad8f539966f.css.gz | Bin 0 -> 42961 bytes
public/editormd/lib/marked.min.backup.js | 18 +
public/katex/katex.min.css | 3 +-
public/katex/katex.min.js | 6 +-
public/react/config/webpack.config.dev.js | 3 +-
public/react/config/webpack.config.prod.js | 5 +-
public/react/public/css/css_min_all.css | 2 +-
public/react/public/css/edu-all.css | 2 +-
public/react/public/css/edu-common.css | 2 +-
.../react/public/js/editormd/editormd.min.js | 7 +
public/react/public/js/js_min_all.js | 4 +-
public/react/public/katex/katex.min.css | 3 +-
public/react/public/katex/katex.min.js | 6 +-
public/react/src/App.css | 3 +
public/react/src/App.js | 1 -
public/react/src/common/TextUtil.js | 4 +-
public/react/src/common/UrlTool.js | 16 +-
.../src/common/components/DragValidator.js | 149 +-
.../components/attachment/AttachmentList.js | 15 +-
public/react/src/common/course/ActionBtn.js | 2 +-
public/react/src/common/educoder.js | 2 +-
.../context/EvaluateSuccessEffectDisplay.js | 2 +-
public/react/src/modules/courses/Index.js | 49 +-
.../src/modules/courses/Resource/index.js | 42 +-
.../src/modules/courses/boards/BoardsNew.js | 37 +-
.../react/src/modules/courses/boards/index.js | 7 +-
.../courses/busyWork/CommonWorkAppraise.js | 12 +-
.../courses/busyWork/CommonWorkDetailIndex.js | 6 +-
.../courses/busyWork/CommonWorkItem.js | 1 +
.../courses/busyWork/CommonWorkList.js | 28 +-
.../busyWork/CommonWorkListTemplate.js | 268 +-
.../courses/busyWork/CommonWorkPost.js | 58 +-
.../courses/busyWork/CommonWorkQuestion.js | 266 +-
.../src/modules/courses/busyWork/NewWork.js | 31 +-
.../courses/busyWork/common/LeaderIcon.js | 11 +-
.../busyWork/common/WorkDetailPageHeader.js | 23 +-
.../modules/courses/busyWork/commonWork.js | 5 +-
.../busyWork/reply/CommonWorkAppraiseReply.js | 9 +-
.../courses/common/comments/CCommentItem.js | 15 +-
.../Completetaskdetails.js | 84 +
.../completetaskdetails/Completetaskpage.js | 138 +
.../completetaskdetails.css | 58 +
.../comtopicdetails/CompletetopicdePage.js | 141 +
.../comtopicdetails/Completetopicdetails.js | 115 +
.../comtopicdetails/completetopicde.css | 58 +
.../courses/coursesDetail/CoursesLeftNav.js | 8 +-
.../courses/coursesPublic/AccessoryModal.js | 7 +-
.../courses/coursesPublic/AccessoryModal2.js | 6 +-
.../courses/coursesPublic/PathModal.js | 11 +-
.../courses/coursesPublic/SelectResource.js | 4 +-
.../courses/coursesPublic/SelectSetting.js | 65 +-
.../courses/coursesPublic/ShixunModal.js | 11 +-
.../courses/coursesPublic/Startshixuntask.js | 3 +-
.../coursesPublic/modal/ShixunModal2.js | 4 +-
.../courses/coursesPublic/sendResource.js | 52 +-
.../react/src/modules/courses/css/Courses.css | 19 +-
.../react/src/modules/courses/css/members.css | 7 +
.../modules/courses/elearning/Elearning.js | 13 +-
.../courses/elearning/YslDetailCards.js | 2 +-
.../courses/exercise/Ecerciseallbackagain.js | 5 +-
.../src/modules/courses/exercise/Exercise.js | 5 +-
.../courses/exercise/ExerciseListItem.js | 1 +
.../exercise/ExerciseReviewAndAnswer.js | 13 +-
.../courses/exercise/Exercisesetting.js | 13 +-
.../exercise/Testpapersettinghomepage.js | 16 +-
.../courses/exercise/new/JudgeEditor.js | 4 +-
.../courses/exercise/question/fillEmpty.js | 6 +-
.../courses/exercise/question/simpleAnswer.js | 4 +-
.../courses/gradinforms/Bullsubdirectory.js | 4 +-
.../modules/courses/gradinforms/Eduinforms.js | 12 +-
.../courses/gradinforms/myysleduinforms.css | 6 +-
.../tasks/GraduationTasksSubmitedit.js | 90 +-
.../tasks/GraduationTasksSubmitnew.js | 25 +-
.../GraduationTasksappraiseMainEditor.js | 39 +-
.../graduation/tasks/GraduationTasksedit.js | 89 +-
.../graduation/tasks/GraduationTasksnew.js | 101 +-
.../tasks/GraduationTaskssetting.js | 3 +-
.../tasks/GraduationTaskssettinglist.js | 73 +-
.../tasks/GraduationTaskssettingquestions.js | 2 +-
.../modules/courses/graduation/tasks/index.js | 5 +-
.../graduation/topics/GraduateTopicDetail.js | 2 +-
.../graduation/topics/GraduateTopicNew.js | 32 +-
.../topics/GraduateTopicPostWorksNew.js | 34 +-
.../courses/graduation/topics/index.js | 5 +-
.../courses/groupjobbank/GroupPackage.js | 87 +
.../courses/groupjobbank/GroupPackage2.js | 73 +
.../groupjobbank/Groupjobbandetails.js | 84 +
.../courses/groupjobbank/GroupjobbankPage.js | 175 +
.../groupjobbank/Groupjobquesanswer.js | 82 +
.../courses/groupjobbank/questionbanks.css | 41 +
.../members/modal/CreateGroupByImportModal.js | 28 +-
.../modules/courses/members/studentsList.js | 157 +-
.../modules/courses/members/teacherList.js | 40 +-
.../src/modules/courses/new/CoursesNew.js | 278 +-
.../src/modules/courses/new/Goldsubject.js | 389 +-
public/react/src/modules/courses/poll/Poll.js | 31 +-
.../courses/poll/PollDetailTabThird.js | 4 +-
.../src/modules/courses/poll/PollListItem.js | 3 +-
.../react/src/modules/courses/poll/PollNew.js | 254 +-
.../courses/questionbank/Generaljobanswer.js | 79 +
.../questionbank/Generaljobbankdetails.js | 173 +
.../courses/questionbank/Generaljobdetails.js | 81 +
.../courses/questionbank/questionbank.css | 26 +
.../shixunHomework/ShixunHomeworkPage.js | 2 +-
.../shixunHomework/ShixunWorkReport.js | 62 +-
.../shixunHomework/ShixunhomeWorkItem.js | 5 +-
.../Shixunworkdetails/ShixunWorkModal.js | 5 +-
.../courses/shixunHomework/shixunHomework.js | 31 +-
.../shixunreport/ConclusionEvaluation.js | 55 +-
.../OfficialAcademicTranscript.js | 150 +-
.../courses/studentWork/StudentHomework.js | 2 +-
.../src/modules/forums/MemoDetailMDEditor.js | 10 +-
public/react/src/modules/forums/MemoNew.js | 1676 +-
.../modules/forums/shixun/ShiXunPostItem.js | 2 +-
.../src/modules/message/js/MessagChat.js | 4 +-
.../src/modules/moop_cases/CaseDetail.js | 4 +-
.../react/src/modules/moop_cases/CaseNew.js | 905 +-
.../react/src/modules/moop_cases/CaseTags.js | 12 +-
.../src/modules/moop_cases/css/moopCases.css | 7 +
public/react/src/modules/page/Index.js | 12 +-
.../src/modules/page/MainContentContainer.js | 4 +-
.../modules/page/component/TPICodeSetting.js | 54 +-
.../modules/paths/PathDetail/DetailCards.js | 2 +-
.../paths/PathDetail/DetailCardsEditAndAdd.js | 5 +-
.../PathDetail/DetailCardsEditAndEdit.js | 5 +-
.../src/modules/paths/PathDetail/DetailTop.js | 34 +-
.../paths/PathDetail/addCollaborators.js | 7 +-
public/react/src/modules/test/ShareTest.js | 35 +
public/react/src/modules/tpm/NewHeader.js | 21 +-
public/react/src/modules/tpm/TPMBanner.js | 5 +-
public/react/src/modules/tpm/TPMIndex.js | 39 +-
public/react/src/modules/tpm/TPMIndexHOC.js | 80 +-
.../src/modules/tpm/TPMRepositoryComponent.js | 7 +
.../TPMUpdatepropaede/TPMUpdatepropaede.js | 134 +-
.../modules/tpm/TPMsettings/TPMsettings.js | 115 +-
.../modules/tpm/challengesnew/TPManswer2.js | 6 +-
.../modules/tpm/challengesnew/TPMquestion.js | 37 +-
.../tpm/challengesnew/TpmQuestionEdit.js | 17 +-
.../tpm/challengesnew/TpmQuestionNew.js | 4 +-
.../src/modules/tpm/component/TPMright.css | 2 +-
.../src/modules/tpm/newshixuns/Newshixuns.js | 49 +-
.../tpm/shixunchild/Challenges/Challenges.js | 2 +-
.../Collaborators/Collaborators.js | 4 +-
.../tpm/shixunchild/Repository/Repository.js | 25 +-
.../Repository/RepositoryAddFile.js | 198 +
.../modules/user/account/AccountBasicEdit.js | 2 +-
.../src/modules/user/usersInfo/InfosBanner.js | 254 +-
.../user/usersInfo/banks/BanksIndex.js | 214 +
public/react/src/scripts/build.js | 189 -
public/react/src/scripts/concat.js | 169 -
public/react/src/scripts/start.js | 114 -
public/react/src/scripts/test.js | 27 -
public/stylesheets/css/edu-common.css | 2 +-
public/stylesheets/educoder/edu-all.css | 11 +-
public/stylesheets/educoder/edu-main.css | 23 +-
.../homework_banks_controller_spec.rb | 5 +
spec/helpers/homework_banks_helper_spec.rb | 15 +
vendor/assets/codemirror/lib/codemirror.css | 349 +
vendor/assets/codemirror/lib/codemirror.js | 9765 ++
vendor/assets/codemirror/mode/shell/shell.js | 152 +
vendor/assets/javascripts/echarts.js | 90302 ++++++++++
403 files changed, 567718 insertions(+), 113686 deletions(-)
create mode 100644 app/assets/javascripts/admins/dashboards/index.js
create mode 100644 app/assets/javascripts/admins/departments/index.js
create mode 100644 app/assets/javascripts/admins/library_applies/index.js
create mode 100644 app/assets/javascripts/admins/mirror_repositories/edit.js
create mode 100644 app/assets/javascripts/admins/mirror_repositories/index.js
create mode 100644 app/assets/javascripts/admins/mirror_scripts/form.js
create mode 100644 app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js
create mode 100644 app/assets/javascripts/admins/modals/admin-edit-department-modal.js
create mode 100644 app/assets/javascripts/admins/modals/admin-merge-department-modal.js
create mode 100644 app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js
create mode 100644 app/assets/javascripts/admins/modals/admin-upload-file-modal.js
create mode 100644 app/assets/javascripts/admins/project_package_applies/project_package_applies.js
create mode 100644 app/assets/javascripts/admins/shixun_settings/index.js
create mode 100644 app/assets/javascripts/admins/shixuns/index.js
create mode 100644 app/assets/javascripts/admins/video_applies/index.js
create mode 100644 app/assets/javascripts/college.js
create mode 100644 app/assets/javascripts/colleges/statistics.js
create mode 100644 app/assets/javascripts/homework_banks.js
create mode 100644 app/assets/stylesheets/admins/dashboards.scss
create mode 100644 app/assets/stylesheets/admins/departments.scss
create mode 100644 app/assets/stylesheets/admins/library_applies.scss
create mode 100644 app/assets/stylesheets/admins/project_package_apply.scss
create mode 100644 app/assets/stylesheets/admins/shixun.scss
create mode 100644 app/assets/stylesheets/admins/shixun_settings.scss
create mode 100644 app/assets/stylesheets/admins/video_apply.scss
create mode 100644 app/assets/stylesheets/college.scss
create mode 100644 app/assets/stylesheets/colleges/statistic.scss
create mode 100644 app/assets/stylesheets/common.scss
create mode 100644 app/assets/stylesheets/homework_banks.scss
create mode 100644 app/controllers/admins/choose_mirror_repositories_controller.rb
create mode 100644 app/controllers/admins/department_members_controller.rb
create mode 100644 app/controllers/admins/departments_controller.rb
create mode 100644 app/controllers/admins/files_controller.rb
create mode 100644 app/controllers/admins/library_applies_controller.rb
create mode 100644 app/controllers/admins/mirror_repositories_controller.rb
create mode 100644 app/controllers/admins/mirror_scripts_controller.rb
create mode 100644 app/controllers/admins/myshixuns_controller.rb
create mode 100644 app/controllers/admins/project_package_applies_controller.rb
create mode 100644 app/controllers/admins/shixun_settings_controller.rb
create mode 100644 app/controllers/admins/shixuns_controller.rb
create mode 100644 app/controllers/admins/video_applies_controller.rb
create mode 100644 app/controllers/colleges_controller.rb
create mode 100644 app/controllers/exercise_bank_questions_controller.rb
create mode 100644 app/controllers/exercise_banks_controller.rb
create mode 100644 app/controllers/gtopic_banks_controller.rb
create mode 100644 app/controllers/homework_banks_controller.rb
create mode 100644 app/controllers/poll_bank_questions_controller.rb
create mode 100644 app/controllers/task_banks_controller.rb
create mode 100644 app/helpers/admins/mirror_repositories_helper.rb
create mode 100644 app/helpers/exercise_bank_questions_helper.rb
create mode 100644 app/helpers/homework_banks_helper.rb
create mode 100644 app/jobs/delete_department_notify_job.rb
create mode 100644 app/models/customer.rb
create mode 100644 app/models/mirror_operation_record.rb
create mode 100644 app/models/partner_customer.rb
create mode 100644 app/queries/admins/department_query.rb
create mode 100644 app/queries/admins/library_apply_query.rb
create mode 100644 app/queries/admins/myshixun_query.rb
create mode 100644 app/queries/admins/shixun_query.rb
create mode 100644 app/queries/admins/shixun_settings_query.rb
create mode 100644 app/services/admins/add_department_member_service.rb
create mode 100644 app/services/admins/check_shixun_mirrors_service.rb
create mode 100644 app/services/admins/choose_mirror_service.rb
create mode 100644 app/services/admins/save_mirror_repository_service.rb
create mode 100644 app/views/admins/choose_mirror_repositories/create.js.erb
create mode 100644 app/views/admins/choose_mirror_repositories/new.js.erb
create mode 100644 app/views/admins/department_members/create.js.erb
create mode 100644 app/views/admins/department_members/destroy.js.erb
create mode 100644 app/views/admins/departments/edit.js.erb
create mode 100644 app/views/admins/departments/index.html.erb
create mode 100644 app/views/admins/departments/index.js.erb
create mode 100644 app/views/admins/departments/shared/_add_department_member_modal.html.erb
create mode 100644 app/views/admins/departments/shared/_create_department_modal.html.erb
create mode 100644 app/views/admins/departments/shared/_department_item.html.erb
create mode 100644 app/views/admins/departments/shared/_edit_department_modal.html.erb
create mode 100644 app/views/admins/departments/shared/_list.html.erb
create mode 100644 app/views/admins/departments/shared/_member_users.html.erb
create mode 100644 app/views/admins/departments/shared/_merge_department_modal.html.erb
create mode 100644 app/views/admins/departments/update.js.erb
create mode 100644 app/views/admins/library_applies/index.html.erb
create mode 100644 app/views/admins/library_applies/index.js.erb
create mode 100644 app/views/admins/library_applies/shared/_list.html.erb
create mode 100644 app/views/admins/mirror_repositories/edit.html.erb
create mode 100644 app/views/admins/mirror_repositories/index.html.erb
create mode 100644 app/views/admins/mirror_repositories/index.js.erb
create mode 100644 app/views/admins/mirror_repositories/merge.js.erb
create mode 100644 app/views/admins/mirror_repositories/new.html.erb
create mode 100644 app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb
create mode 100644 app/views/admins/mirror_repositories/shared/_form.html.erb
create mode 100644 app/views/admins/mirror_repositories/shared/_list.html.erb
create mode 100644 app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb
create mode 100644 app/views/admins/mirror_scripts/edit.html.erb
create mode 100644 app/views/admins/mirror_scripts/index.html.erb
create mode 100644 app/views/admins/mirror_scripts/new.html.erb
create mode 100644 app/views/admins/mirror_scripts/shared/_form.html.erb
create mode 100644 app/views/admins/mirror_scripts/shared/_list.html.erb
create mode 100644 app/views/admins/myshixuns/index.html.erb
create mode 100644 app/views/admins/myshixuns/index.js.erb
create mode 100644 app/views/admins/myshixuns/shared/_list.html.erb
create mode 100644 app/views/admins/project_package_applies/index.html.erb
create mode 100644 app/views/admins/project_package_applies/index.js.erb
create mode 100644 app/views/admins/project_package_applies/shared/_list.html.erb
create mode 100644 app/views/admins/shared/403.html.erb
create mode 100644 app/views/admins/shared/modal/_upload_file_modal.html.erb
create mode 100644 app/views/admins/shixun_settings/index.html.erb
create mode 100644 app/views/admins/shixun_settings/index.js.erb
create mode 100644 app/views/admins/shixun_settings/shared/_list.html.erb
create mode 100644 app/views/admins/shixun_settings/shared/_td.html.erb
create mode 100644 app/views/admins/shixun_settings/update.js.erb
create mode 100644 app/views/admins/shixuns/index.html.erb
create mode 100644 app/views/admins/shixuns/index.js.erb
create mode 100644 app/views/admins/shixuns/shared/_list.html.erb
create mode 100644 app/views/admins/users/index.json.jbuilder
create mode 100644 app/views/admins/video_applies/index.html.erb
create mode 100644 app/views/admins/video_applies/index.js.erb
create mode 100644 app/views/admins/video_applies/shared/_list.html.erb
create mode 100644 app/views/colleges/_course_statistics.html.erb
create mode 100644 app/views/colleges/_student_rank.html.erb
create mode 100644 app/views/colleges/_teacher_rank.html.erb
create mode 100644 app/views/colleges/course_statistics.js.erb
create mode 100644 app/views/colleges/shared/_navbar.html.erb
create mode 100644 app/views/colleges/statistics.html.erb
create mode 100644 app/views/colleges/student_shixun.js.erb
create mode 100644 app/views/colleges/teachers.js.erb
create mode 100644 app/views/courses/export_course_info.xlsx.axlsx
create mode 100644 app/views/courses/export_member_act_score.xlsx.axlsx
create mode 100644 app/views/exercise_bank_questions/_exercise_bank_questions.json.jbuilder
create mode 100644 app/views/exercise_banks/choose_shixun.json.jbuilder
create mode 100644 app/views/exercise_banks/commit_shixun.json.jbuilder
create mode 100644 app/views/exercise_banks/show.json.jbuilder
create mode 100644 app/views/gtopic_banks/edit.json.jbuilder
create mode 100644 app/views/gtopic_banks/show.json.jbuilder
create mode 100644 app/views/homework_banks/show.json.jbuilder
create mode 100644 app/views/layouts/college.html.erb
create mode 100644 app/views/question_banks/my_courses.json.jbuilder
create mode 100644 app/views/shixuns/add_file.json.jbuilder
create mode 100644 app/views/task_banks/show.json.jbuilder
create mode 100644 config/locales/library_applies/zh-CN.yml
create mode 100644 db/migrate/20190828011222_add_update_user_id_to_student_works.rb
create mode 100644 db/migrate/20190828055710_add_is_ordered_to_exercise_bank_question.rb
create mode 100644 db/migrate/20190829025855_migrate_gtopic_bank_is_public.rb
create mode 100644 db/migrate/20190829084147_migrate_course_group_position.rb
create mode 100644 db/migrate/20190830064803_add_announcement_to_course_modules.rb
create mode 100644 db/migrate/20190830082934_add_tag_to_libraries.rb
create mode 100644 db/migrate/20190831014325_migrate_poll_bank_question.rb
create mode 100644 lib/tasks/public_course_zhp.rake
delete mode 100644 public/assets/.sprockets-manifest-1c370772f16743f825981ab0e5c94237.json
create mode 100644 public/assets/.sprockets-manifest-fd1f19755cf79ae07a20ee9d2676d85e.json
create mode 100644 public/assets/admin-07f89a76946f8ce796dafa51fbda5443521854cd6fe7eecf750cf443f1e699c9.css
create mode 100644 public/assets/admin-07f89a76946f8ce796dafa51fbda5443521854cd6fe7eecf750cf443f1e699c9.css.gz
delete mode 100644 public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js
delete mode 100644 public/assets/admin-6575f1399953fb1935c037a7b8bd28c4aff07b70bed9b41faf6899a89af4b57d.js.gz
create mode 100644 public/assets/admin-81f6ac4c1ad5e53b10117d319ac4a62d8b76f65baf7b06fdedc47323635bcdaf.js
create mode 100644 public/assets/admin-81f6ac4c1ad5e53b10117d319ac4a62d8b76f65baf7b06fdedc47323635bcdaf.js.gz
delete mode 100644 public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css
delete mode 100644 public/assets/admin-8a2b03cb8a055dc63f45443b304cae77382331beba55b1570b3d3c8aa42442d5.css.gz
create mode 100644 public/assets/application-1bce1740cf43111049b991ad4d5537a46deb578488e47bbb006d551b54f72895.css
create mode 100644 public/assets/application-1bce1740cf43111049b991ad4d5537a46deb578488e47bbb006d551b54f72895.css.gz
create mode 100644 public/assets/application-830ab01de7cd41145be3bd392304541807c3ea985eb566bdabdbafee7f6c6735.js
create mode 100644 public/assets/application-830ab01de7cd41145be3bd392304541807c3ea985eb566bdabdbafee7f6c6735.js.gz
delete mode 100644 public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js
delete mode 100644 public/assets/application-a3a4f3549d68670572bb07700c85a9ac11e536edc73fef6e7489723bf535e533.js.gz
delete mode 100644 public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css
delete mode 100644 public/assets/application-a7508b88eb6a69a5b301602bddc14745cec09853ea7d91c6fae856b96e788f46.css.gz
create mode 100644 public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js
create mode 100644 public/assets/college-18f5e8400331634e898a35acc2187815c096c25e0ab74aba341ae916166cd287.js.gz
create mode 100644 public/assets/college-279b722d063f61aec89f1ad6f44c4a620f522278a4668cc218465ad8f539966f.css
create mode 100644 public/assets/college-279b722d063f61aec89f1ad6f44c4a620f522278a4668cc218465ad8f539966f.css.gz
create mode 100644 public/editormd/lib/marked.min.backup.js
create mode 100644 public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js
create mode 100644 public/react/src/modules/courses/completetaskdetails/Completetaskpage.js
create mode 100644 public/react/src/modules/courses/completetaskdetails/completetaskdetails.css
create mode 100644 public/react/src/modules/courses/comtopicdetails/CompletetopicdePage.js
create mode 100644 public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js
create mode 100644 public/react/src/modules/courses/comtopicdetails/completetopicde.css
create mode 100644 public/react/src/modules/courses/groupjobbank/GroupPackage.js
create mode 100644 public/react/src/modules/courses/groupjobbank/GroupPackage2.js
create mode 100644 public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js
create mode 100644 public/react/src/modules/courses/groupjobbank/GroupjobbankPage.js
create mode 100644 public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js
create mode 100644 public/react/src/modules/courses/groupjobbank/questionbanks.css
create mode 100644 public/react/src/modules/courses/questionbank/Generaljobanswer.js
create mode 100644 public/react/src/modules/courses/questionbank/Generaljobbankdetails.js
create mode 100644 public/react/src/modules/courses/questionbank/Generaljobdetails.js
create mode 100644 public/react/src/modules/courses/questionbank/questionbank.css
create mode 100644 public/react/src/modules/test/ShareTest.js
create mode 100644 public/react/src/modules/tpm/shixunchild/Repository/RepositoryAddFile.js
create mode 100644 public/react/src/modules/user/usersInfo/banks/BanksIndex.js
delete mode 100644 public/react/src/scripts/build.js
delete mode 100644 public/react/src/scripts/concat.js
delete mode 100644 public/react/src/scripts/start.js
delete mode 100644 public/react/src/scripts/test.js
create mode 100644 spec/controllers/homework_banks_controller_spec.rb
create mode 100644 spec/helpers/homework_banks_helper_spec.rb
create mode 100644 vendor/assets/codemirror/lib/codemirror.css
create mode 100644 vendor/assets/codemirror/lib/codemirror.js
create mode 100644 vendor/assets/codemirror/mode/shell/shell.js
create mode 100644 vendor/assets/javascripts/echarts.js
diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js
index 72a2ff118..12b89804b 100644
--- a/app/assets/javascripts/admin.js
+++ b/app/assets/javascripts/admin.js
@@ -13,15 +13,32 @@
//= require bootstrap-datepicker
//= require bootstrap.viewer
+//= require echarts
+//= require lib/codemirror
+//= require mode/shell/shell
+
//= require_tree ./i18n
//= require_tree ./admins
+
+$.ajaxSetup({
+ beforeSend: function(xhr) {
+ xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
+ }
+});
+
// ******** select2 global config ********
$.fn.select2.defaults.set('theme', 'bootstrap4');
$.fn.select2.defaults.set('language', 'zh-CN');
Turbolinks.setProgressBarDelay(200);
+$.notifyDefaults({
+ type: 'success',
+ z_index: 9999,
+ delay: 2000
+});
+
$(document).on('turbolinks:load', function(){
$('[data-toggle="tooltip"]').tooltip();
$('[data-toggle="popover"]').popover();
@@ -32,11 +49,18 @@ $(document).on('turbolinks:load', function(){
// flash alert提示框自动关闭
if($('.admin-alert-container .alert').length > 0){
setTimeout(function(){
- $('.admin-alert-container .alert').alert('close');
+ $('.admin-alert-container .alert:not(.alert-danger)').alert('close');
}, 2000);
+ setTimeout(function(){
+ $('.admin-alert-container .alert.alert-danger').alert('close');
+ }, 5000);
}
});
+$(document).on("turbolinks:before-cache", function () {
+ $('[data-toggle="tooltip"]').tooltip('hide');
+ $('[data-toggle="popover"]').popover('hide');
+});
// var progressBar = new Turbolinks.ProgressBar();
// $(document).on('ajax:send', function(event){
diff --git a/app/assets/javascripts/admins/common-refuse-modal.js b/app/assets/javascripts/admins/common-refuse-modal.js
index 5eb2f3f46..4e1af891e 100644
--- a/app/assets/javascripts/admins/common-refuse-modal.js
+++ b/app/assets/javascripts/admins/common-refuse-modal.js
@@ -27,10 +27,11 @@ $(document).on('turbolinks:load', function() {
});
// modal visited fire
$refuseModal.on('shown.bs.modal', function(){
- $refuseModal.find('.modal-body input[name="reason"]').focus();
+ $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', '');
})
diff --git a/app/assets/javascripts/admins/dashboards/index.js b/app/assets/javascripts/admins/dashboards/index.js
new file mode 100644
index 000000000..ab9cde3fc
--- /dev/null
+++ b/app/assets/javascripts/admins/dashboards/index.js
@@ -0,0 +1,66 @@
+$(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 : [
+ {
+ name: '访问来源',
+ type: 'pie',
+ radius: '55%',
+ data: []
+ }
+ ]
+ });
+ 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();
+ // });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/departments/index.js b/app/assets/javascripts/admins/departments/index.js
new file mode 100644
index 000000000..eb0fc3a6a
--- /dev/null
+++ b/app/assets/javascripts/admins/departments/index.js
@@ -0,0 +1,173 @@
+$(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');
+ });
+
+ // ============== 新建部门 ===============
+ 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');
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ school_id: {
+ required: true
+ },
+ department_name: {
+ required: true
+ }
+ },
+ messages: {
+ school_id: {
+ required: '请选择所属单位'
+ }
+ }
+ });
+
+ // 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;
+ };
+
+ 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;
+ },
+ matcher: matcherFunc
+ });
+ }
+
+ $.ajax({
+ url: '/api/schools/for_option.json',
+ dataType: 'json',
+ type: 'GET',
+ success: function(data) {
+ defineSchoolSelect(data.schools);
+ }
+ });
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+
+ if ($form.valid()) {
+ var url = $form.data('url');
+
+ $.ajax({
+ method: 'POST',
+ dataType: 'json',
+ url: url,
+ data: $form.serialize(),
+ success: function(){
+ $.notify({ message: '创建成功' });
+ $modal.modal('hide');
+
+ setTimeout(function(){
+ window.location.reload();
+ }, 500);
+ },
+ error: function(res){
+ var data = res.responseJSON;
+ $form.find('.error').html(data.message);
+ }
+ });
+ }
+ });
+
+ // ============= 添加部门管理员 ==============
+ 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"]')
+
+ $addMemberModal.on('show.bs.modal', function(event){
+ var $link = $(event.relatedTarget);
+ var departmentId = $link.data('department-id');
+ $departmentIdInput.val(departmentId);
+
+ $memberSelect.select2('val', ' ');
+ });
+
+ $memberSelect.select2({
+ theme: 'bootstrap4',
+ placeholder: '请输入要添加的管理员姓名',
+ multiple: true,
+ minimumInputLength: 1,
+ ajax: {
+ delay: 500,
+ url: '/admins/users',
+ dataType: 'json',
+ data: function(params){
+ return { name: params.term };
+ },
+ processResults: function(data){
+ return { results: data.users }
+ }
+ },
+ templateResult: function (item) {
+ if(!item.id || item.id === '') return item.text;
+ return item.real_name;
+ },
+ templateSelection: function(item){
+ if (item.id) {
+ }
+ return item.real_name || item.text;
+ }
+ });
+
+ $addMemberModal.on('click', '.submit-btn', function(){
+ $addMemberForm.find('.error').html('');
+
+ var departmentId = $departmentIdInput.val();
+ var memberIds = $memberSelect.val();
+ if (departmentId && memberIds && memberIds.length > 0) {
+ $.ajax({
+ method: 'POST',
+ dataType: 'script',
+ url: '/admins/departments/' + departmentId + '/department_member',
+ data: { user_ids: memberIds }
+ });
+ } else {
+ $addMemberModal.modal('hide');
+ }
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/library_applies/index.js b/app/assets/javascripts/admins/library_applies/index.js
new file mode 100644
index 000000000..ab0fc35e2
--- /dev/null
+++ b/app/assets/javascripts/admins/library_applies/index.js
@@ -0,0 +1,20 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-library-applies-index-page').length > 0) {
+ var $searchFrom = $('.library-applies-list-form');
+ $searchFrom.find('select[name="status"]').val('pending');
+
+ $searchFrom.on('click', '.search-form-tab', function(){
+ var $link = $(this);
+
+ $searchFrom.find('input[name="keyword"]').val('');
+ $searchFrom.find('select[name="status"]').val('processed');
+
+ if($link.data('value') === 'processed'){
+ $searchFrom.find('.status-filter').show();
+ } else {
+ $searchFrom.find('.status-filter').hide();
+ $searchFrom.find('select[name="status"]').val('pending');
+ }
+ });
+ }
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/mirror_repositories/edit.js b/app/assets/javascripts/admins/mirror_repositories/edit.js
new file mode 100644
index 000000000..7fb3ad10d
--- /dev/null
+++ b/app/assets/javascripts/admins/mirror_repositories/edit.js
@@ -0,0 +1,19 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-mirror-repositories-edit-page, body.admins-mirror-repositories-update-page').length > 0) {
+ var $form = $('form.edit-mirror');
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ "mirror_repository[type_name]": {
+ required: true
+ }
+ }
+ });
+
+ $form.submit(function(e){
+ if(!$form.valid()){ e.preventDefault(); }
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/mirror_repositories/index.js b/app/assets/javascripts/admins/mirror_repositories/index.js
new file mode 100644
index 000000000..2e30bdd94
--- /dev/null
+++ b/app/assets/javascripts/admins/mirror_repositories/index.js
@@ -0,0 +1,4 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-mirror-repositories-index-page').length > 0) {
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/mirror_scripts/form.js b/app/assets/javascripts/admins/mirror_scripts/form.js
new file mode 100644
index 000000000..3aa318d8d
--- /dev/null
+++ b/app/assets/javascripts/admins/mirror_scripts/form.js
@@ -0,0 +1,33 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-mirror-scripts-edit-page, body.admins-mirror-scripts-update-page, body.admins-mirror-scripts-new-page, body.admins-mirror-scripts-create-page').length > 0) {
+ var $form = $('form.script-form');
+
+ // codemirror编辑器
+ var scriptEditor = CodeMirror.fromTextArea(document.getElementById('mirror_script_script'), {
+ lineNumbers: true,
+ mode: 'shell',
+ theme: "default",
+ indentUnit: 4, //代码缩进为一个tab的距离
+ matchBrackets: true,
+ autoRefresh: true,
+ smartIndent: true,//智能换行
+ styleActiveLine: true,
+ lint: true
+ });
+ scriptEditor.setSize('auto', '600px');
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ "mirror_script[script_type]": {
+ required: true
+ }
+ }
+ });
+
+ $form.submit(function(e){
+ if(!$form.valid()){ e.preventDefault(); }
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js b/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js
new file mode 100644
index 000000000..6111b2401
--- /dev/null
+++ b/app/assets/javascripts/admins/modals/admin-choose-mirror-modal.js
@@ -0,0 +1,32 @@
+$(document).on('turbolinks:load', function() {
+ $('.admin-modal-container').on('show.bs.modal', '.modal.admin-choose-mirror-modal', function(){
+ var $modal = $('.modal.admin-choose-mirror-modal');
+ var $form = $modal.find('form.admin-choose-mirror-form');
+
+ var validateForm = function(){
+ var checkedValue = $form.find('input[name="mirror_number"]:checked').val();
+
+ if(checkedValue == undefined){
+ $modal.find('.error').html('必须选择一种镜像保存!');
+ return false;
+ }
+ return true;
+ }
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+ var url = $form.attr('action');
+
+ if (validateForm()) {
+ $.ajax({
+ method: 'POST',
+ dataType: 'script',
+ url: url,
+ data: $form.serialize(),
+ }).done(function(){
+ $modal.modal('hide');
+ });
+ }
+ });
+ })
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/modals/admin-edit-department-modal.js b/app/assets/javascripts/admins/modals/admin-edit-department-modal.js
new file mode 100644
index 000000000..a1df01ba5
--- /dev/null
+++ b/app/assets/javascripts/admins/modals/admin-edit-department-modal.js
@@ -0,0 +1,34 @@
+$(document).on('turbolinks:load', function() {
+ $('.admin-modal-container').on('show.bs.modal', '.modal.admin-edit-department-modal', function(){
+ var $modal = $('.modal.admin-edit-department-modal');
+ var $form = $modal.find('form.admin-edit-department-form');
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ 'department[name]': {
+ required: true,
+ maxlength: 20
+ },
+ 'department[host_count]': {
+ digits: true
+ }
+ }
+ });
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+ var url = $form.attr('action');
+
+ if ($form.valid()) {
+ $.ajax({
+ method: 'PATCH',
+ dataType: 'script',
+ url: url,
+ data: $form.serialize()
+ });
+ }
+ });
+ })
+});
\ 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
new file mode 100644
index 000000000..aead3f485
--- /dev/null
+++ b/app/assets/javascripts/admins/modals/admin-merge-department-modal.js
@@ -0,0 +1,110 @@
+$(document).on('turbolinks:load', function() {
+ var $modal = $('.modal.admin-merge-department-modal');
+ if ($modal.length > 0) {
+ var $form = $modal.find('form.admin-merge-department-form');
+ var $schoolIdInput = $form.find('input[name="school_id"]');
+ var $originDepartmentIdInput = $form.find('input[name="origin_department_id"]');
+ var $departmentSelect = $modal.find('.department-select');
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ department_id: {
+ required: true
+ }
+ },
+ messages: {
+ department_id: {
+ required: '请选择部门'
+ }
+ }
+ });
+
+ // ************** 学校选择 *************
+ 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;
+ };
+
+ var defineDepartmentSelect = function(departments) {
+ $departmentSelect.empty();
+
+ $departmentSelect.select2({
+ theme: 'bootstrap4',
+ placeholder: '请选择所属部门',
+ data: departments,
+ templateResult: function (item) {
+ if(!item.id || item.id === '') return item.text;
+ return item.name;
+ },
+ templateSelection: function(item){
+ if (item.id) {
+ $form.find('#department_id').val(item.id);
+ }
+ return item.name || item.text;
+ },
+ matcher: matcherFunc
+ });
+ $departmentSelect.select2('val', ' ');
+ };
+
+ // modal ready fire
+ $modal.on('show.bs.modal', function (event) {
+ var $link = $(event.relatedTarget);
+
+ var schoolId = $link.data('schoolId');
+
+ $schoolIdInput.val(schoolId);
+ $originDepartmentIdInput.val($link.data('departmentId'));
+
+ $.ajax({
+ url: '/api/schools/' + schoolId + '/departments/for_option.json',
+ dataType: 'json',
+ type: 'GET',
+ success: function(data) {
+ defineDepartmentSelect(data.departments);
+ }
+ });
+ });
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+
+ if ($form.valid()) {
+ var url = $form.data('url');
+
+ $.ajax({
+ method: 'POST',
+ dataType: 'json',
+ url: url,
+ data: $form.serialize(),
+ success: function(){
+ $.notify({ message: '操作成功' });
+ $modal.modal('hide');
+
+ setTimeout(function(){
+ window.location.reload();
+ }, 500);
+ },
+ error: function(res){
+ 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-replace-mirror-modal.js b/app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js
new file mode 100644
index 000000000..8b7a129a6
--- /dev/null
+++ b/app/assets/javascripts/admins/modals/admin-replace-mirror-modal.js
@@ -0,0 +1,89 @@
+$(document).on('turbolinks:load', function() {
+ var $modal = $('.modal.admin-replace-mirror-modal');
+ if ($modal.length > 0) {
+ var $form = $modal.find('form.admin-replace-mirror-form');
+ var $mirrorIdInput = $modal.find('.modal-body input[name="mirror_id"]');
+ var $mirrorSelect = $modal.find('.new-mirror-select');
+
+ var setMirror = function(id, name){
+ $mirrorIdInput.val(id);
+ $form.find('.mirror-id-container').html(id);
+ $form.find('.mirror-name-container').html(name);
+ }
+
+ $form.validate({
+ errorElement: 'span',
+ errorClass: 'danger text-danger',
+ rules: {
+ new_mirror_id: {
+ required: true
+ },
+ },
+ messages: {
+ new_mirror_id: {
+ required: '请选择新镜像'
+ }
+ }
+ });
+
+ // modal ready fire
+ $modal.on('show.bs.modal', function (event) {
+ var $link = $(event.relatedTarget);
+
+ var mirrorId = $link.data('id');
+ var mirrorName = $link.data('name');
+
+ setMirror(mirrorId, mirrorName);
+ $mirrorSelect.select2('val', ' ');
+ });
+ $modal.on('hide.bs.modal', function () {
+ setMirror('', '');
+ $mirrorSelect.select2('val', ' ');
+ $('#new_mirror_id-error').remove();
+ });
+
+ $mirrorSelect.select2({
+ theme: 'bootstrap4',
+ placeholder: '输入要合并的镜像名',
+ minimumInputLength: 1,
+ ajax: {
+ url: '/admins/mirror_repositories/for_select',
+ dataType: 'json',
+ data: function(params){
+ return { keyword: params.term };
+ },
+ processResults: function(data){
+ return { results: data.mirrors }
+ }
+ },
+ templateResult: function (item) {
+ if(!item.id || item.id === '') return item.text;
+ return item.name;
+ },
+ templateSelection: function(item){
+ if (item.id) {
+ $('#new_mirror_id-error').remove();
+ $('#new_mirror_id').val(item.id);
+ }
+ return item.name || item.text;
+ }
+ });
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+
+ if ($form.valid()) {
+ var url = $form.data('url');
+
+ $.ajax({
+ method: 'POST',
+ dataType: 'script',
+ url: url,
+ data: $form.serialize(),
+ }).done(function(){
+ $modal.modal('hide');
+ });
+ }
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/modals/admin-upload-file-modal.js b/app/assets/javascripts/admins/modals/admin-upload-file-modal.js
new file mode 100644
index 000000000..cf1333381
--- /dev/null
+++ b/app/assets/javascripts/admins/modals/admin-upload-file-modal.js
@@ -0,0 +1,62 @@
+$(document).on('turbolinks:load', function() {
+ var $modal = $('.modal.admin-upload-file-modal');
+ if ($modal.length > 0) {
+ var $form = $modal.find('form.admin-upload-file-form')
+ var $sourceIdInput = $modal.find('input[name="source_id"]');
+ var $sourceTypeInput = $modal.find('input[name="source_type"]');
+
+ $modal.on('show.bs.modal', function(event){
+ var $link = $(event.relatedTarget);
+ var sourceId = $link.data('sourceId');
+ var sourceType = $link.data('sourceType');
+
+ $sourceIdInput.val(sourceId);
+ $sourceTypeInput.val(sourceType);
+
+ $modal.find('.upload-file-input').trigger('click');
+ });
+
+ $modal.find('.upload-file-input').on('change', function(e){
+ var file = $(this)[0].files[0];
+
+ if(file){
+ $modal.find('.file-names').html(file.name);
+ $modal.find('.submit-btn').trigger('click');
+ }
+ })
+
+ var formValid = 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;
+ };
+
+ $modal.on('click', '.submit-btn', function(){
+ $form.find('.error').html('');
+
+ if (formValid()) {
+ var formDataString = $form.serialize();
+ $.ajax({
+ method: 'POST',
+ dataType: 'json',
+ url: '/admins/files?' + formDataString,
+ data: new FormData($form[0]),
+ processData: false,
+ contentType: false,
+ success: function(data){
+ $.notify({ message: '上传成功' });
+ $modal.trigger('upload:success', data);
+ $modal.modal('hide');
+ },
+ error: function(res){
+ var data = res.responseJSON;
+ $form.find('.error').html(data.message);
+ }
+ });
+ }
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/project_package_applies/project_package_applies.js b/app/assets/javascripts/admins/project_package_applies/project_package_applies.js
new file mode 100644
index 000000000..153ad1f66
--- /dev/null
+++ b/app/assets/javascripts/admins/project_package_applies/project_package_applies.js
@@ -0,0 +1,20 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-project-package-applies-index-page').length > 0) {
+ var $searchFrom = $('.project-package-applies-form');
+ $searchFrom.find('select[name="status"]').val('pending');
+
+ $searchFrom.on('click', '.search-form-tab', function(){
+ var $link = $(this);
+
+ $searchFrom.find('input[name="keyword"]').val('');
+ $searchFrom.find('select[name="status"]').val('all');
+
+ if($link.data('value') === 'all'){
+ $searchFrom.find('.status-filter').show();
+ } else {
+ $searchFrom.find('.status-filter').hide();
+ $searchFrom.find('select[name="status"]').val('pending');
+ }
+ });
+ }
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/shixun_settings/index.js b/app/assets/javascripts/admins/shixun_settings/index.js
new file mode 100644
index 000000000..f99574673
--- /dev/null
+++ b/app/assets/javascripts/admins/shixun_settings/index.js
@@ -0,0 +1,44 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-shixun-settings-index-page').length > 0) {
+ let searchContainer = $(".shixun-settings-list-form");
+ let searchForm = $("form.search-form",searchContainer);
+
+ searchContainer.on('change', '.shixun-settings-select', function(){
+ searchForm.find('input[type="submit"]').trigger('click');
+ });
+
+ //导出
+ searchContainer.on('click',"#shixun-settings-export",function () {
+ window.location.href = "/admins/shixun_settings.xls?" + searchForm.serialize();
+ });
+
+ $(".shixun-settings-list-container").on("change", '.shixun-setting-form', function () {
+ var s_id = $(this).attr("data-id");
+ var s_value = $(this).val();
+ var s_name = $(this).attr("name");
+ var json = {};
+ var s_index = $(this).parent("td").siblings(".shixun-line-no").text();
+ json[s_name] = s_value;
+ json["page_no"] = s_index;
+ $.ajax({
+ url: "/admins/shixun_settings/" + s_id,
+ type: "PUT",
+ dataType:'script',
+ data: json
+ })
+ });
+
+ $("select#settings-tag-choosed").select2({
+ placeholder: "请选择分类",
+ allowClear: true
+ });
+
+ $('.modal.admin-upload-file-modal').on('upload:success', function(e, data){
+ var $imageElement = $('.shixun-image-' + data.source_id);
+ $imageElement.attr('src', data.url);
+ $imageElement.show();
+ $imageElement.next().html('重新上传');
+ })
+ }
+});
+
diff --git a/app/assets/javascripts/admins/shixuns/index.js b/app/assets/javascripts/admins/shixuns/index.js
new file mode 100644
index 000000000..849e13b5b
--- /dev/null
+++ b/app/assets/javascripts/admins/shixuns/index.js
@@ -0,0 +1,14 @@
+$(document).on('turbolinks:load', function() {
+ if($('body.admins-shixuns-index-page').length > 0){
+ $('select#tag-choosed').select2({
+ placeholder: "请选择分类",
+ allowClear: true
+ });
+
+ let search_form = $(".search-form");
+ //导出
+ $(".shixuns-list-form").on("click","#shixuns-export",function () {
+ window.location.href = "/admins/shixuns.xls?" + search_form.serialize();
+ });
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/admins/video_applies/index.js b/app/assets/javascripts/admins/video_applies/index.js
new file mode 100644
index 000000000..2e72acd97
--- /dev/null
+++ b/app/assets/javascripts/admins/video_applies/index.js
@@ -0,0 +1,20 @@
+$(document).on('turbolinks:load', function() {
+ if ($('body.admins-video-applies-index-page').length > 0) {
+ var $searchFrom = $('.video-applies-form');
+ $searchFrom.find('select[name="status"]').val('pending');
+
+ $searchFrom.on('click', '.search-form-tab', function(){
+ var $link = $(this);
+
+ $searchFrom.find('input[name="keyword"]').val('');
+ $searchFrom.find('select[name="status"]').val('all');
+
+ if($link.data('value') === 'all'){
+ $searchFrom.find('.status-filter').show();
+ } else {
+ $searchFrom.find('.status-filter').hide();
+ $searchFrom.find('select[name="status"]').val('pending');
+ }
+ });
+ }
+})
\ No newline at end of file
diff --git a/app/assets/javascripts/college.js b/app/assets/javascripts/college.js
new file mode 100644
index 000000000..8f99236a5
--- /dev/null
+++ b/app/assets/javascripts/college.js
@@ -0,0 +1,21 @@
+//= require rails-ujs
+//= require turbolinks
+//= require jquery3
+//= require popper
+//= require bootstrap-sprockets
+
+//= require echarts
+
+//= require_tree ./colleges
+
+Turbolinks.setProgressBarDelay(200);
+
+$(document).on('turbolinks:load', function() {
+ $('[data-toggle="tooltip"]').tooltip();
+ $('[data-toggle="popover"]').popover();
+})
+
+$(document).on("turbolinks:before-cache", function () {
+ $('[data-toggle="tooltip"]').tooltip('hide');
+ $('[data-toggle="popover"]').popover('hide');
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/colleges/statistics.js b/app/assets/javascripts/colleges/statistics.js
new file mode 100644
index 000000000..6e2790df1
--- /dev/null
+++ b/app/assets/javascripts/colleges/statistics.js
@@ -0,0 +1,156 @@
+$(document).on('turbolinks:load', function() {
+ if($('body.colleges-statistics-page').length > 0) {
+ var $statisticBody = $('.statistics-body');
+ var $statisticBase = $('.statistic-base');
+ var schoolId = $statisticBody.data('id');
+ var $statisticCourse = $statisticBody.find('.statistic-course')
+ var $shixunChart = $statisticBody.find('.shixun-chart');
+
+ $.get('/colleges/' + schoolId + '/shixun_time', function(data){
+ $statisticBase.find('.shixun-time').html("" + data.shixun_time + " 天");
+ });
+ $.get('/colleges/' + schoolId + '/shixun_report_count', function(data){
+ $statisticBase.find('.shixun-report-count').html("" + data.shixun_report_count + " 个");
+ });
+
+ $.ajax({ url: '/colleges/' + schoolId + '/course_statistics', method: 'GET', dataType: 'script' });
+ $.ajax({ url: '/colleges/' + schoolId + '/teachers', method: 'GET', dataType: 'script' });
+
+ var initShixunChart = function(names, data){
+ var shixunChart = echarts.init(document.getElementById('shixun-chart'));
+ var options = {
+ series : [
+ {
+ name: '访问来源',
+ type: 'pie',
+ radius: '55%',
+ data: data
+ }
+ ]
+ };
+
+ shixunChart.setOption(options);
+ };
+ $.get('/colleges/' + schoolId + '/shixun_chart_data', function(data){
+ $statisticBody.find('.shixun-chart-loading').hide();
+ if (data.data.length > 0) {
+ $shixunChart.css('height', '400px').css('width', '100%');
+ initShixunChart(data.names, data.data);
+ } else {
+ $statisticBody.find('.shixun-chart-empty').show();
+ }
+ });
+
+ $.ajax({ url: '/colleges/' + schoolId + '/student_shixun', method: 'GET', dataType: 'script' });
+
+ var initHotEvaluating = function(names, values){
+ var Color = ['#962e66', '#623363', '#CCCCCC', '#9A9A9A', '#FF8080', '#FF80C2', '#B980FF', '#80B9FF', '#6FE9FF', '#4DE8B4', '#F8EF63', '#FFB967'];
+
+ var option = {
+ backgroundColor: '#fff',
+ grid: {
+ left: '3%',
+ right: '4%',
+ bottom: '10%',
+ containLabel: true
+ },
+
+ 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: 'value',
+ axisTick: {
+ show: false
+ },
+ axisLine: {
+ show: true,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ splitLine: {
+ show: false,
+ lineStyle: {
+ color: '#CCCCCC'
+ }
+ },
+ axisLabel: {
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ },
+ formatter: '{value}'
+ }
+ },
+ yAxis: {
+ type: 'category',
+ axisLine: {
+ lineStyle: {
+ color: '#cccccc'
+ }
+ },
+ splitLine: {
+ show: false
+ },
+ axisTick: {
+ show: false
+ },
+ splitArea: {
+ show: false
+ },
+ axisLabel: {
+ inside: false,
+ textStyle: {
+ color: '#656565',
+ fontWeight: 'normal',
+ fontSize: '12'
+ }
+ },
+ data: names
+ },
+ series: [{
+ name: '',
+ type: 'bar',
+ itemStyle: {
+ normal: {
+ show: true,
+ color: function(params) {
+ return Color[params.dataIndex]
+ },
+ barBorderRadius: 50,
+ borderWidth: 0,
+ borderColor: '#333'
+ }
+ },
+ barGap: '0%',
+ barCategoryGap: '50%',
+ data: values
+ }
+
+ ]
+ };
+ var myChart = echarts.init(document.getElementById('hot-chart'));
+ myChart.setOption(option);
+ }
+
+ $.get('/colleges/' + schoolId + '/student_hot_evaluations', function(data){
+ $statisticBody.find('.hot-chart-loading').hide();
+ if (data.names.length > 0) {
+ $statisticBody.find('.hot-chart').css('height', '400px').css('width', '100%');
+ initHotEvaluating(data.names.reverse(), data.values.reverse());
+ } else {
+ $statisticBody.find('.hot-chart-empty').show();
+ }
+ })
+ }
+});
\ No newline at end of file
diff --git a/app/assets/javascripts/homework_banks.js b/app/assets/javascripts/homework_banks.js
new file mode 100644
index 000000000..dee720fac
--- /dev/null
+++ b/app/assets/javascripts/homework_banks.js
@@ -0,0 +1,2 @@
+// Place all the behaviors and hooks related to the matching controller here.
+// All this logic will automatically be available in application.js.
diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss
index 0aa1329ca..d3a298dcf 100644
--- a/app/assets/stylesheets/admin.scss
+++ b/app/assets/stylesheets/admin.scss
@@ -5,7 +5,9 @@
@import "select2-bootstrap4.min";
@import "bootstrap-datepicker";
@import "bootstrap-datepicker.standalone";
+@import "lib/codemirror";
+@import "common";
@import "admins/*";
body {
@@ -17,20 +19,7 @@ body {
align-items: stretch;
font-size: 14px;
background: #efefef;
-}
-
-a {
- &:hover {
- text-decoration: unset;
- }
-}
-
-textarea.danger, input.danger {
- border-color: #dc3545!important;
-}
-
-label.error {
- color: #dc3545!important;
+ overflow: hidden;
}
.simple_form {
@@ -45,6 +34,16 @@ label.error {
}
}
-.flex-1 {
- flex: 1;
-}
\ No newline at end of file
+input.form-control {
+ font-size: 14px;
+}
+
+.btn-default{
+ color: #666;
+ background: #e1e1e1!important;
+}
+.export-absolute{
+ right:20px;
+ position: absolute;
+}
+.position-r{position:relative;}
diff --git a/app/assets/stylesheets/admins/common.scss b/app/assets/stylesheets/admins/common.scss
index 2254166fd..56b286981 100644
--- a/app/assets/stylesheets/admins/common.scss
+++ b/app/assets/stylesheets/admins/common.scss
@@ -106,5 +106,9 @@
padding: 0.5rem 2rem;
}
}
+
+ .CodeMirror {
+ border: 1px solid #ced4da;
+ }
}
diff --git a/app/assets/stylesheets/admins/dashboards.scss b/app/assets/stylesheets/admins/dashboards.scss
new file mode 100644
index 000000000..d401b7f62
--- /dev/null
+++ b/app/assets/stylesheets/admins/dashboards.scss
@@ -0,0 +1,7 @@
+.admins-dashboards-index-page {
+ .pie-statistic {
+ .pie {
+ height: 300px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/departments.scss b/app/assets/stylesheets/admins/departments.scss
new file mode 100644
index 000000000..7d9d078e5
--- /dev/null
+++ b/app/assets/stylesheets/admins/departments.scss
@@ -0,0 +1,24 @@
+.admins-departments-index-page {
+ .department-list-table {
+ .member-container {
+ .member-user {
+ display: flex;
+ justify-content: center;
+ flex-wrap: wrap;
+
+ .member-user-item {
+ display: flex;
+ align-items: center;
+ height: 22px;
+ line-height: 22px;
+ padding: 2px 5px;
+ margin: 2px 2px;
+ border: 1px solid #91D5FF;
+ background-color: #E6F7FF;
+ color: #91D5FF;
+ border-radius: 4px;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/library_applies.scss b/app/assets/stylesheets/admins/library_applies.scss
new file mode 100644
index 000000000..23b7ce30a
--- /dev/null
+++ b/app/assets/stylesheets/admins/library_applies.scss
@@ -0,0 +1,9 @@
+.admins-library-applies-index-page {
+ .library-applies-list-container {
+ span {
+ &.apply-status-agreed { color: #28a745; }
+ &.apply-status-refused { color: #dc3545; }
+ &.apply-status-processed { color: #6c757d; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/project_package_apply.scss b/app/assets/stylesheets/admins/project_package_apply.scss
new file mode 100644
index 000000000..a6daac205
--- /dev/null
+++ b/app/assets/stylesheets/admins/project_package_apply.scss
@@ -0,0 +1,9 @@
+.admins-project-package-applies-index-page {
+ .project-package-applies-list-container {
+ span {
+ &.apply-status-agreed { color: #28a745; }
+ &.apply-status-refused { color: #dc3545; }
+ &.apply-status-processed { color: #6c757d; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/shixun.scss b/app/assets/stylesheets/admins/shixun.scss
new file mode 100644
index 000000000..75f8a54b5
--- /dev/null
+++ b/app/assets/stylesheets/admins/shixun.scss
@@ -0,0 +1,7 @@
+.admins-shixuns-index-page{
+ .shixuns-list-container{
+ .shixuns-status-1 { color: #6c757d; }
+ .shixuns-status-2 { color: #28a745; }
+ .shixuns-status-3 { color: #dc3545; }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/shixun_settings.scss b/app/assets/stylesheets/admins/shixun_settings.scss
new file mode 100644
index 000000000..dcfc35650
--- /dev/null
+++ b/app/assets/stylesheets/admins/shixun_settings.scss
@@ -0,0 +1,22 @@
+.admins-shixun-settings-index-page {
+ input[type="checkbox"]{
+ font-size:18px;
+ }
+ .select2 input::-webkit-input-placeholder{
+ color:#ccc;
+ }
+ .select2 .select2-selection__choice{
+ border: 1px solid #eee !important;
+ }
+ .setting-chosen{
+ font-weight: 400;
+ font-size: 10px;
+ color:#333;
+ }
+
+ .shixun-setting-image {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/admins/video_apply.scss b/app/assets/stylesheets/admins/video_apply.scss
new file mode 100644
index 000000000..993ea1b8f
--- /dev/null
+++ b/app/assets/stylesheets/admins/video_apply.scss
@@ -0,0 +1,9 @@
+.admins-video-applies-index-page {
+ .video-applies-list-container {
+ span {
+ &.apply-status-agreed { color: #28a745; }
+ &.apply-status-refused { color: #dc3545; }
+ &.apply-status-processed { color: #6c757d; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/college.scss b/app/assets/stylesheets/college.scss
new file mode 100644
index 000000000..8e0ca0e10
--- /dev/null
+++ b/app/assets/stylesheets/college.scss
@@ -0,0 +1,13 @@
+@import "bootstrap";
+@import "font-awesome-sprockets";
+@import "font-awesome";
+
+@import "common";
+
+@import "colleges/*";
+
+
+.navbar-dark .navbar-nav .nav-link {
+ color: rgba(255, 255, 255, 1);
+ font-size: 16px;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/colleges/statistic.scss b/app/assets/stylesheets/colleges/statistic.scss
new file mode 100644
index 000000000..c3e63e845
--- /dev/null
+++ b/app/assets/stylesheets/colleges/statistic.scss
@@ -0,0 +1,135 @@
+.colleges-statistics-page {
+ .college-body-container {
+ .statistic-header {
+ width: 100%;
+ height: 240px;
+ background-image: url('/images/educoder/statistics.jpg');
+ background-size: 100% 100%;
+
+ &-container {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ &-title {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ color: #4CACFF;
+ font-size: 32px;
+ }
+
+ &-content {
+ width: 100%;
+ display: flex;
+ justify-content: space-around;
+ }
+
+ &-item {
+ margin-bottom: 22px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ color: #fff;
+
+ &-label {
+ color: #989898;
+ }
+
+ &-content {
+ font-size: 24px;
+ }
+ }
+ }
+
+ .statistic-box {
+ border: unset;
+ box-shadow: 0px 0px 9px rgba(174, 175, 177, 0.2);
+ }
+
+ .statistic-base {
+ &-title {
+ padding: 2rem 1.25rem;
+ background: #fff;
+ border-bottom: unset;
+ }
+
+ &-table {
+ margin: 0;
+ padding: 0;
+ }
+
+ &-item {
+ padding: 0;
+
+ &-label {
+ text-align: center;
+ font-size: 16px;
+ height: 48px;
+ line-height: 48px;
+ color: #686868;
+ background: #F5F5F5;
+ border-top: 1px solid #EBEBEB;
+ border-bottom: 1px solid #EBEBEB;
+ }
+
+ &-content {
+ height: 100px;
+ font-size: 16px;
+ text-align: center;
+ line-height: 100px;
+
+ span {
+ margin-right: 5px;
+ font-size: 24px;
+ }
+ }
+ }
+ }
+
+ .statistic-container {
+ padding: 0;
+ background: #fff;
+ border-radius: 3px;
+ box-shadow: 0px 0px 9px rgba(174, 175, 177, 0.2);
+
+ .statistic-label {
+ padding: 2rem 1.25rem;
+ font-size: 1.5rem;
+ }
+
+ .statistic-table {
+ overflow-x: scroll;
+ table.course-table { min-width: 1100px; }
+ table.teacher-rank-table { min-width: 640px; }
+ }
+
+ table th {
+ background: #F5F5F5;
+ border-color: #EBEBEB;
+ }
+
+ &.statistic-course {
+ min-height: 400px;
+ }
+
+ &.statistic-teacher-rank, &.statistic-student-rank {
+ min-height: 500px;
+ }
+ }
+
+ .statistic-chart {
+ padding: 0 20px;
+ height: 400px;
+
+ .shixun-chart-loading, .shixun-chart-empty, .hot-chart-loading, .hot-chart-empty {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 100%;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss
new file mode 100644
index 000000000..3310ec828
--- /dev/null
+++ b/app/assets/stylesheets/common.scss
@@ -0,0 +1,36 @@
+body {
+ font-size: 14px;
+ background: #efefef;
+}
+
+a {
+ &:hover {
+ text-decoration: unset;
+ }
+}
+
+textarea.danger, input.danger {
+ border-color: #dc3545!important;
+}
+
+label.error {
+ color: #dc3545!important;
+}
+
+input.form-control {
+ font-size: 14px;
+}
+.input-group-prepend {
+ .input-group-text {
+ font-size: 14px;
+ }
+}
+
+.flex-1 {
+ flex: 1;
+}
+
+.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
diff --git a/app/assets/stylesheets/homework_banks.scss b/app/assets/stylesheets/homework_banks.scss
new file mode 100644
index 000000000..0cfbbd32d
--- /dev/null
+++ b/app/assets/stylesheets/homework_banks.scss
@@ -0,0 +1,3 @@
+// Place all the styles related to the homework_banks 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/select2-bootstrap4.min.scss b/app/assets/stylesheets/select2-bootstrap4.min.scss
index f84b4090a..c39ca0195 100644
--- a/app/assets/stylesheets/select2-bootstrap4.min.scss
+++ b/app/assets/stylesheets/select2-bootstrap4.min.scss
@@ -1 +1 @@
-.select2-container--bootstrap4 .select2-selection--single{height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder{color:#757575;line-height:calc(1.5em + .75rem)}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow{position:absolute;top:50%;right:3px;width:20px}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b{top:60%;border-color:#343a40 transparent transparent;border-style:solid;border-width:5px 4px 0;width:0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute}.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered{line-height:calc(1.5em + .75rem)}.select2-search--dropdown .select2-search__field{border:1px solid #ced4da;border-radius:.25rem}.select2-results__message{color:#6c757d}.select2-container--bootstrap4 .select2-selection--multiple{min-height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice{color:#343a40;border:1px solid #bdc6d0;border-radius:.2rem;padding:0 5px 0 0;cursor:pointer;float:left;margin-top:.3em;margin-right:5px}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove{color:#bdc6d0;font-weight:700;margin-left:3px;margin-right:1px;padding-right:3px;padding-left:3px;float:left}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover{color:#343a40}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--bootstrap4{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.input-group-prepend~.select2-container--bootstrap4 .select2-selection{border-top-left-radius:0;border-bottom-left-radius:0}.select2-container--bootstrap4 .select2-selection{border:1px solid #ced4da;border-radius:.25rem;width:100%}.select2-container--bootstrap4.select2-container--focus .select2-selection{border-color:#17a2b8;-webkit-box-shadow:0 0 0 .2rem rgba(0,123,255,.25);box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection,.select2-container--bootstrap4.select2-container--disabled .select2-selection{background-color:#e9ecef;cursor:not-allowed;border-color:#ced4da;-webkit-box-shadow:none;box-shadow:none}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field,.select2-container--bootstrap4.select2-container--disabled .select2-search__field{background-color:transparent}form.was-validated select:invalid~.select2-container--bootstrap4 .select2-selection,select.is-invalid~.select2-container--bootstrap4 .select2-selection{border-color:#dc3545}form.was-validated select:valid~.select2-container--bootstrap4 .select2-selection,select.is-valid~.select2-container--bootstrap4 .select2-selection{border-color:#28a745}.select2-container--bootstrap4 .select2-dropdown{border-color:#ced4da;border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above{border-top:1px solid #ced4da;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#e9ecef}.select2-container--bootstrap4 .select2-results__option--highlighted,.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:#007bff;color:#f8f9fa}.select2-container--bootstrap4 .select2-results__option[role=group]{padding:0}.select2-container--bootstrap4 .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--bootstrap4 .select2-results__group{padding:6px;display:list-item;color:#6c757d}.select2-container--bootstrap4 .select2-selection__clear{width:1.2em;height:1.2em;line-height:1.15em;padding-left:.3em;margin-top:.5em;border-radius:100%;background-color:#6c757d;color:#f8f9fa;float:right;margin-right:.3em}.select2-container--bootstrap4 .select2-selection__clear:hover{background-color:#343a40}
\ No newline at end of file
+.select2-container--bootstrap4 .select2-selection--single{height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--single .select2-selection__placeholder{color:#757575;line-height:calc(1.5em + .75rem)}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow{position:absolute;top:50%;right:3px;width:20px}.select2-container--bootstrap4 .select2-selection--single .select2-selection__arrow b{top:60%;border-color:#343a40 transparent transparent;border-style:solid;border-width:5px 4px 0;width:0;height:0;left:50%;margin-left:-4px;margin-top:-2px;position:absolute}.select2-container--bootstrap4 .select2-selection--single .select2-selection__rendered{line-height:calc(1.5em + .75rem)}.select2-search--dropdown .select2-search__field{border:1px solid #ced4da;border-radius:.25rem}.select2-results__message{color:#6c757d}.select2-container--bootstrap4 .select2-selection--multiple{min-height:calc(1.5em + .75rem + 2px)!important}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__rendered{-webkit-box-sizing:border-box;box-sizing:border-box;list-style:none;margin:0;padding:0 5px;width:100%}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice{color:#343a40;border:1px solid #bdc6d0;border-radius:.2rem;padding:0 5px 0 0;cursor:pointer;float:left;margin-top:.3em;margin-right:5px}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove{color:#bdc6d0;font-weight:700;margin-left:3px;margin-right:1px;padding-right:3px;padding-left:3px;float:left}.select2-container--bootstrap4 .select2-selection--multiple .select2-selection__choice__remove:hover{color:#343a40}.select2-container{display:block}.select2-container :focus{outline:0}.input-group .select2-container--bootstrap4{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.input-group-prepend~.select2-container--bootstrap4 .select2-selection{border-top-left-radius:0;border-bottom-left-radius:0}.select2-container--bootstrap4 .select2-selection{border:1px solid #ced4da;border-radius:.25rem;width:100%}.select2-container--bootstrap4.select2-container--focus .select2-selection{border-color:#17a2b8;-webkit-box-shadow:0 0 0 .2rem rgba(0,123,255,.25);box-shadow:0 0 0 .2rem rgba(0,123,255,.25)}.select2-container--bootstrap4.select2-container--focus.select2-container--open .select2-selection{border-bottom:none;border-bottom-left-radius:0;border-bottom-right-radius:0}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-selection,.select2-container--bootstrap4.select2-container--disabled .select2-selection{background-color:#e9ecef;cursor:not-allowed;border-color:#ced4da;-webkit-box-shadow:none;box-shadow:none}.select2-container--bootstrap4.select2-container--disabled.select2-container--focus .select2-search__field,.select2-container--bootstrap4.select2-container--disabled .select2-search__field{background-color:transparent}form.was-validated select:invalid~.select2-container--bootstrap4 .select2-selection,select.is-invalid~.select2-container--bootstrap4 .select2-selection{border-color:#dc3545}form.was-validated select:valid~.select2-container--bootstrap4 .select2-selection,select.is-valid~.select2-container--bootstrap4 .select2-selection{border-color:#28a745}.select2-container--bootstrap4 .select2-dropdown{border-color:#ced4da;border-top:none;border-top-left-radius:0;border-top-right-radius:0}.select2-container--bootstrap4 .select2-dropdown.select2-dropdown--above{border-top:1px solid #ced4da;border-top-left-radius:.25rem;border-top-right-radius:.25rem}.select2-container--bootstrap4 .select2-dropdown .select2-results__option[aria-selected=true]{background-color:#e9ecef}.select2-container--bootstrap4 .select2-results__option--highlighted,.select2-container--bootstrap4 .select2-results__option--highlighted.select2-results__option[aria-selected=true]{background-color:#007bff;color:#f8f9fa}.select2-container--bootstrap4 .select2-results__option[role=group]{padding:0}.select2-container--bootstrap4 .select2-results>.select2-results__options{max-height:15em;overflow-y:auto}.select2-container--bootstrap4 .select2-results__group{padding:6px;display:list-item;color:#6c757d}.select2-container--bootstrap4 .select2-selection__clear{width:1.2em;height:1.2em;line-height:1.15em;padding-left:.3em;margin-top:.5em;border-radius:100%;background-color:#ccc;color:#f8f9fa;float:right;margin-right:.3em}.select2-container--bootstrap4 .select2-selection__clear:hover{background-color:#343a40}
\ No newline at end of file
diff --git a/app/controllers/admins/choose_mirror_repositories_controller.rb b/app/controllers/admins/choose_mirror_repositories_controller.rb
new file mode 100644
index 000000000..c178e0d76
--- /dev/null
+++ b/app/controllers/admins/choose_mirror_repositories_controller.rb
@@ -0,0 +1,11 @@
+class Admins::ChooseMirrorRepositoriesController < Admins::BaseController
+ def new
+ @mirror = MirrorRepository.find(params[:mirror_id])
+ @new_mirror = MirrorOperationRecord.where(mirror_repository_id: @mirror.id, status: 1, user_id: -1).first
+ end
+
+ def create
+ mirror = MirrorRepository.find(params[:mirror_id])
+ Admins::ChooseMirrorService.call(mirror, current_user, params[:mirror_number])
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/dashboards_controller.rb b/app/controllers/admins/dashboards_controller.rb
index 5d5d6b184..3971971ff 100644
--- a/app/controllers/admins/dashboards_controller.rb
+++ b/app/controllers/admins/dashboards_controller.rb
@@ -1,4 +1,51 @@
class Admins::DashboardsController < Admins::BaseController
def index
+ @active_user_count = User.where(last_login_on: today).count
+ @weekly_active_user_count = User.where(last_login_on: current_week).count
+ @month_active_user_count = User.where(last_login_on: current_month).count
+
+ @new_user_count = User.where(created_on: current_month).count
+ end
+
+ def month_active_user
+ count = UserExtension.where(created_at: current_month).group(:identity).count
+
+ data = [
+ { value: count['teacher'].to_i, name: '老师' },
+ { value: count['student'].to_i, name: '学生' },
+ { value: count['professional'].to_i, name: '专业人士' },
+ { value: count[nil].to_i, name: '未选职业' },
+ ]
+
+ render_ok(data: data)
+ end
+
+ def evaluate
+ names = []
+ data = []
+
+ 1.upto(7) do |i|
+ date = i.days.ago
+ names.unshift(date.strftime('%Y-%m-%d'))
+
+ count = Output.where(created_at: date.beginning_of_day..date.end_of_day).count
+ data.unshift(count)
+ end
+
+ render_ok(names: names, data: data)
+ end
+
+ private
+
+ def today
+ Time.now.beginning_of_day..Time.now.end_of_day
+ end
+
+ def current_week
+ 7.days.ago.beginning_of_day..Time.now.end_of_day
+ end
+
+ def current_month
+ 30.days.ago.beginning_of_day..Time.now.end_of_day
end
end
\ No newline at end of file
diff --git a/app/controllers/admins/department_members_controller.rb b/app/controllers/admins/department_members_controller.rb
new file mode 100644
index 000000000..ba483acef
--- /dev/null
+++ b/app/controllers/admins/department_members_controller.rb
@@ -0,0 +1,20 @@
+class Admins::DepartmentMembersController < Admins::BaseController
+
+ helper_method :current_department
+
+ def create
+ Admins::AddDepartmentMemberService.call(current_department, params)
+ current_department.reload
+ end
+
+ def destroy
+ @member = current_department.department_members.find_by(user_id: params[:user_id])
+ @member.destroy! if @member.present?
+ end
+
+ private
+
+ def current_department
+ @_current_department ||= Department.find(params[:department_id])
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/departments_controller.rb b/app/controllers/admins/departments_controller.rb
new file mode 100644
index 000000000..ed7c3d3db
--- /dev/null
+++ b/app/controllers/admins/departments_controller.rb
@@ -0,0 +1,95 @@
+class Admins::DepartmentsController < Admins::BaseController
+
+ helper_method :current_department
+
+ def index
+ params[:sort_by] ||= 'created_at'
+ params[:sort_direction] ||= 'desc'
+
+ departments = Admins::DepartmentQuery.call(params)
+
+ @departments = paginate departments.preload(:school, :member_users)
+
+ department_ids = @departments.map(&:id)
+ @users_count = UserExtension.where(department_id: department_ids).group(:department_id).count
+ @professional_auth_count = UserExtension.where(department_id: department_ids)
+ .joins(:user).where(users: { professional_certification: true })
+ .group(:department_id).count
+ end
+
+ def create
+ department_name = params[:department_name].to_s.strip
+ school = School.find(params[:school_id])
+
+ return render_error('部门名称重复') if school.departments.exists?(name: department_name)
+
+ ActiveRecord::Base.transaction do
+ department = school.departments.create!(name: department_name, is_auth: 1)
+ ApplyAddDepartment.create!(school_id: school.id, status: 1, name: department.name,
+ department_id: department.id, user_id: current_user.id)
+ end
+
+ render_ok
+ end
+
+ def edit
+ end
+
+ def update
+ identifier = update_params.delete(:identifier).presence
+ if identifier && Department.where.not(id: current_department.id).exists?(identifier: identifier)
+ return render_error('统计链接重复', type: :notify)
+ end
+
+ current_department.update!(update_params.merge(identifier: identifier))
+ end
+
+ def destroy
+ ActiveRecord::Base.transaction do
+ current_department.apply_add_departments.update_all(status: 2)
+
+ user_ids = current_department.user_extensions.pluck(:user_id)
+ if user_ids.present?
+ DeleteDepartmentNotifyJob.perform_later(current_department.id, 0, user_ids)
+ current_department.soft_delete!
+ else
+ current_department.destroy!
+ end
+ end
+
+ render_delete_success
+ end
+
+ def merge
+ return render_error('请选择其它部门') if params[:origin_department_id].to_s == params[:department_id].to_s
+
+ origin_department = Department.find(params[:origin_department_id])
+ to_department = Department.find(params[:department_id])
+
+ return render_error('部门所属单位不相同') if origin_department.school_id != to_department.school_id
+
+ ActiveRecord::Base.transaction do
+ origin_department.apply_add_departments.delete_all
+
+ origin_department.user_extensions.update_all(department_id: to_department.id)
+
+ if to_department.identifier.blank? && origin_department.identifier.present?
+ to_department.update!(identifier: origin_department.identifier)
+ end
+
+ origin_department.destroy!
+ end
+
+ render_ok
+ end
+
+ private
+
+ def current_department
+ @_current_department ||= Department.find(params[:id])
+ end
+
+ def update_params
+ params.require(:department).permit(:name, :identifier, :host_count)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/files_controller.rb b/app/controllers/admins/files_controller.rb
new file mode 100644
index 000000000..3c799ceba
--- /dev/null
+++ b/app/controllers/admins/files_controller.rb
@@ -0,0 +1,54 @@
+class Admins::FilesController < Admins::BaseController
+ before_action :convert_file!, only: [:create]
+
+ def create
+ File.delete(file_path) if File.exist?(file_path) # 删除之前的文件
+
+ Util.write_file(@file, file_path)
+
+ render_ok(source_id: params[:source_id], source_type: params[:source_type].to_s, url: file_url)
+ rescue StandardError => ex
+ logger_error(ex)
+ render_error('上传失败')
+ end
+
+ private
+
+ def convert_file!
+ max_size = 10 * 1024 * 1024 # 10M
+ if params[:file].class == ActionDispatch::Http::UploadedFile
+ @file = params[:file]
+ render_error('请上传文件') if @file.size.zero?
+ render_error('文件大小超过限制') if @file.size > max_size
+ else
+ file = params[: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
+
+ def file_path
+ @_file_path ||= begin
+ case params[:source_type].to_s
+ when 'Shixun' then
+ disk_filename('Shixun', params[:source_id])
+ else
+ 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)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/library_applies_controller.rb b/app/controllers/admins/library_applies_controller.rb
new file mode 100644
index 000000000..678dc31ad
--- /dev/null
+++ b/app/controllers/admins/library_applies_controller.rb
@@ -0,0 +1,25 @@
+class Admins::LibraryAppliesController < Admins::BaseController
+ def index
+ params[:status] ||= 'pending'
+ applies = Admins::LibraryApplyQuery.call(params)
+
+ @library_applies = paginate applies.preload(library: :user)
+ end
+
+ def agree
+ Libraries::AgreeApplyService.new(current_library_apply, current_user).call
+ render_success_js
+ end
+
+ def refuse
+ Libraries::RefuseApplyService.new(current_library_apply, current_user, reason: params[:reason]).call
+
+ render_success_js
+ end
+
+ private
+
+ def current_library_apply
+ @_current_library_apply ||= LibraryApply.find(params[:id])
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/mirror_repositories_controller.rb b/app/controllers/admins/mirror_repositories_controller.rb
new file mode 100644
index 000000000..aed8dc09e
--- /dev/null
+++ b/app/controllers/admins/mirror_repositories_controller.rb
@@ -0,0 +1,97 @@
+class Admins::MirrorRepositoriesController < Admins::BaseController
+ before_action :check_shixun_mirrors!, only: [:index]
+
+ def index
+ mirrors = MirrorRepository.all
+ mirrors = mirrors.reorder(status: :desc, main_type: :desc, type_name: :asc)
+
+ @mirrors = paginate mirrors.includes(:mirror_scripts)
+ @error_mirror_names = MirrorRepository.where(status: 5).pluck(:name)
+ end
+
+ def new
+ @mirror = MirrorRepository.new
+ end
+
+ def create
+ @mirror = MirrorRepository.new
+ Admins::SaveMirrorRepositoryService.call(@mirror, current_user, form_params)
+
+ flash[:success] = '保存成功'
+ redirect_to edit_admins_mirror_repository_path(@mirror)
+ rescue ActiveRecord::RecordInvalid
+ flash.now[:danger] = '保存失败'
+ render 'new'
+ rescue Admins::SaveMirrorRepositoryService::Error => ex
+ flash.now[:danger] = ex.message
+ render 'new'
+ end
+
+ def edit
+ @mirror = current_mirror
+ end
+
+ def update
+ @mirror = current_mirror
+
+ Admins::SaveMirrorRepositoryService.call(current_mirror, current_user, form_params)
+
+ flash[:success] = '保存成功'
+ redirect_to edit_admins_mirror_repository_path(current_mirror)
+ rescue ActiveRecord::RecordInvalid
+ flash.now[:danger] = '保存失败'
+ render 'edit'
+ rescue Admins::SaveMirrorRepositoryService::Error => ex
+ flash.now[:danger] = ex.message
+ render 'edit'
+ end
+
+ def destroy
+ return render_js_error('该状态下不允许删除') unless current_mirror.deletable?
+
+ current_mirror.destroy!
+
+ render_delete_success
+ end
+
+ def for_select
+ mirrors = MirrorRepository.all
+
+ keyword = params[:keyword].to_s.strip
+ mirrors = mirrors.where('name LIKE ?', "%#{keyword}%") if keyword.present?
+
+ @mirrors = paginate mirrors
+
+ render_ok(count: @mirrors.total_count, mirrors: @mirrors.as_json(only: %i[id name]))
+ end
+
+ def merge
+ origin_mirror = MirrorRepository.find(params[:mirror_id])
+ mirror = MirrorRepository.find(params[:new_mirror_id])
+
+ ActiveRecord::Base.transaction do
+ origin_mirror.update!(name: mirror.name, mirrorID: mirror.mirrorID)
+ mirror.destroy!
+ end
+ end
+
+ private
+
+ def current_mirror
+ @_current_mirror ||= MirrorRepository.find(params[:id])
+ end
+
+ def form_params
+ columns = %i[type_name main_type time_limit resource_limit cpu_limit memory_limit description status]
+ params.require(:mirror_repository).permit(*columns)
+ end
+
+ def check_shixun_mirrors!
+ return
+ return unless request.format.html?
+
+ Admins::CheckShixunMirrorsService.call
+ rescue Admins::CheckShixunMirrorsService::Error => e
+ internal_server_error(e.message)
+ end
+end
diff --git a/app/controllers/admins/mirror_scripts_controller.rb b/app/controllers/admins/mirror_scripts_controller.rb
new file mode 100644
index 000000000..9ed3611f4
--- /dev/null
+++ b/app/controllers/admins/mirror_scripts_controller.rb
@@ -0,0 +1,59 @@
+class Admins::MirrorScriptsController < Admins::BaseController
+ helper_method :current_mirror
+
+ def index
+ scripts = current_mirror.mirror_scripts.order(updated_at: :desc)
+ @scripts = paginate scripts
+ end
+
+ def new
+ @script = current_mirror.mirror_scripts.new
+ end
+
+ def create
+ @script = current_mirror.mirror_scripts.new(form_params)
+
+ if @script.save
+ flash[:success] = '保存成功'
+ redirect_to edit_admins_mirror_repository_mirror_script_path(current_mirror, @script)
+ else
+ flash[:danger] = '保存失败'
+ render 'new'
+ end
+ end
+
+ def edit
+ @script = current_script
+ end
+
+ def update
+ @script = current_script
+
+ if @script.update(form_params)
+ flash[:success] = '保存成功'
+ redirect_to edit_admins_mirror_repository_mirror_script_path(current_mirror, @script)
+ else
+ flash[:danger] = '保存失败'
+ render 'edit'
+ end
+ end
+
+ def destroy
+ current_script.destroy!
+ render_delete_success
+ end
+
+ private
+
+ def current_script
+ @_current_script ||= current_mirror.mirror_scripts.find(params[:id])
+ end
+
+ def current_mirror
+ @_current_mirror ||= MirrorRepository.find(params[:mirror_repository_id])
+ end
+
+ def form_params
+ params.require(:mirror_script).permit(:script_type, :description, :script)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/myshixuns_controller.rb b/app/controllers/admins/myshixuns_controller.rb
new file mode 100644
index 000000000..f70a64554
--- /dev/null
+++ b/app/controllers/admins/myshixuns_controller.rb
@@ -0,0 +1,14 @@
+class Admins::MyshixunsController < Admins::BaseController
+ def index
+ params[:sort_by] = params[:sort_by].presence || 'created_at'
+ params[:sort_direction] = params[:sort_direction].presence || 'desc'
+
+ myshixuns = Admins::MyshixunQuery.call(params)
+
+ @myshixuns = paginate myshixuns.includes(:last_executable_task, :last_task, shixun: :user, user: { user_extension: :school })
+
+ myshixun_ids = @myshixuns.map(&:id)
+ @finish_game_count = Game.where(myshixun_id: myshixun_ids, status: 2).group(:myshixun_id).count
+ @total_score = Game.where(myshixun_id: myshixun_ids, status: 2).where('final_score > 0').group(:myshixun_id).sum(:final_score)
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/project_package_applies_controller.rb b/app/controllers/admins/project_package_applies_controller.rb
new file mode 100644
index 000000000..12347d30c
--- /dev/null
+++ b/app/controllers/admins/project_package_applies_controller.rb
@@ -0,0 +1,37 @@
+class Admins::ProjectPackageAppliesController < Admins::BaseController
+ before_action :current_apply,only: [:agree,:refuse]
+
+ def index
+ params[:status] ||= 'pending'
+ status = params[:status]
+ if status == 'all'
+ status = %w(agreed refused)
+ end
+ package_applies = ProjectPackageApply.where(status: status)
+ keyword = params[:keyword].to_s.strip || ""
+ if keyword.present?
+ package_applies = package_applies.joins(:project_package).where("project_packages.title like ?","%#{keyword}%")
+ end
+ @package_applies = paginate package_applies.includes(project_package: { creator: :user_extension })
+ end
+
+ def agree
+ ProjectPackages::AgreeApplyService.new(current_apply).call
+ render_success_js
+ rescue ProjectPackages::AgreeApplyService::Error => e
+ render json: { status: -1, message: e.message }
+ end
+
+ def refuse
+ ProjectPackages::RefuseApplyService.new(current_apply, reason: params[:reason]).call
+ render_success_js
+ rescue ProjectPackages::RefuseApplyService::Error => e
+ render json: { status: -1, message: e.message }
+ end
+
+ private
+
+ def current_apply
+ @_current_apply ||= ProjectPackageApply.find(params[:id])
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/admins/shixun_settings_controller.rb b/app/controllers/admins/shixun_settings_controller.rb
new file mode 100644
index 000000000..0ccd5725d
--- /dev/null
+++ b/app/controllers/admins/shixun_settings_controller.rb
@@ -0,0 +1,97 @@
+class Admins::ShixunSettingsController < Admins::BaseController
+
+ def index
+ params[:sort_by] = params[:sort_by].presence || 'created_on'
+ params[:sort_direction] = params[:sort_direction].presence || 'desc'
+
+ shixun_settings = Admins::ShixunSettingsQuery.call(params)
+ @editing_shixuns = shixun_settings.where(status:0).size
+ @pending_shixuns = shixun_settings.where(status:1).size
+ @processed_shixuns = shixun_settings.where(status:2).size
+ @closed_shixuns = shixun_settings.where(status:3).size
+
+ @sort_json = {
+ can_copy: params[:can_copy].present? ? params[:can_copy] : false,
+ webssh: params[:webssh].present? ? params[:webssh] : "0",
+ hidden: params[:hidden].present? ? params[:hidden] : false,
+ homepage_show: params[:homepage_show].present? ? params[:homepage_show] : false,
+ task_pass: params[:task_pass].present? ? params[:task_pass] : false,
+ code_hidden: params[:code_hidden].present? ? params[:code_hidden] : false
+ }
+
+ @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
+ @shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id)
+ @params_page = params[:page] || 1
+ @shixun_settings = paginate shixun_settings.preload(:user,:tag_repertoires)
+
+ respond_to do |format|
+ format.js
+ format.html
+ format.xls{
+ filename = "实训详情_#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}.xls"
+ send_data(shixun_list_xls(shixun_settings), :type => 'application/octet-stream', :filename => filename_for_content_disposition(filename))
+ }
+ end
+
+ end
+
+ def update
+ @shixun = Shixun.find_by(id:params[:id])
+ @page_no = params[:page_no] || "1"
+ @shixun_tags = TagRepertoire.order("name asc").pluck(:name,:id)
+ tag_ids = params[:tag_repertoires]
+ if tag_ids.present?
+ @shixun&.shixun_tag_repertoires.delete_all
+ tag_repertoire_ids = @shixun&.tag_repertoires&.pluck(:id)
+ tag_ids.each do |id|
+ unless tag_repertoire_ids.include?(id)
+ tag_repertoire = @shixun.shixun_tag_repertoires.new(shixun_id:@shixun.id,tag_repertoire_id:id)
+ tag_repertoire.save
+ end
+ end
+ else
+ unless @shixun.update_attributes(setting_params)
+ redirect_to admins_shixun_settings_path
+ flash[:danger] = "更新失败"
+ end
+ end
+ end
+
+ private
+ def shixun_list_xls shixuns
+ xls_report = StringIO.new
+ book = Spreadsheet::Workbook.new
+ sheet1 = book.create_worksheet :name => "sheet"
+ blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
+ sheet1.row(0).default_format = blue
+ sheet1.row(0).concat(["实训ID","实训名称","技术平台", "Fork源", "实践任务","选择题任务","挑战人数", "通关人数", "状态","创建者", "单位", "职业", "关卡序号","关卡名称","技能标签"])
+ count_row = 1
+ shixuns.find_each do |shixun|
+ sheet1[count_row, 0] = shixun.identifier
+ sheet1[count_row, 1] = shixun.name
+ sheet1[count_row, 2] = shixun.shixun_main_name
+ sheet1[count_row, 3] = shixun.fork_identifier
+ sheet1[count_row, 4] = shixun.challenges.practice_type.count
+ sheet1[count_row, 5] = shixun.challenges.choose_type.count
+ sheet1[count_row, 6] = shixun.myshixuns.count
+ sheet1[count_row, 7] = shixun.myshixuns.finished.count
+ sheet1[count_row, 8] = shixun.shixun_status
+ sheet1[count_row, 9] = shixun.owner.show_real_name
+ sheet1[count_row, 10] = shixun.owner.school_name
+ sheet1[count_row, 11] = shixun.owner.identity
+ shixun.challenges.each do |challenge|
+ sheet1[count_row, 12] = "第#{challenge.position}关"
+ sheet1[count_row, 13] = challenge.subject
+ sheet1[count_row, 14] = challenge.tags_show
+ count_row += 1
+ end
+ count_row += 1
+ end
+ book.write xls_report
+ xls_report.string
+ end
+
+ def setting_params
+ params.permit(:use_scope,:excute_time,:close,:status,:can_copy,:webssh,:hidden,:homepage_show,:task_pass,:code_hidden,:id,tag_repertoires:[])
+ end
+end
diff --git a/app/controllers/admins/shixuns_controller.rb b/app/controllers/admins/shixuns_controller.rb
new file mode 100644
index 000000000..a4aa8a044
--- /dev/null
+++ b/app/controllers/admins/shixuns_controller.rb
@@ -0,0 +1,64 @@
+class Admins::ShixunsController < Admins::BaseController
+
+ def index
+ params[:sort_by] = params[:sort_by].presence || 'created_on'
+ params[:sort_direction] = params[:sort_direction].presence || 'desc'
+ shixuns = Admins::ShixunQuery.call(params)
+ @editing_shixuns = shixuns.where(status:0).size
+ @pending_shixuns = shixuns.where(status:1).size
+ @processed_shixuns = shixuns.where(status:2).size
+ @closed_shixuns = shixuns.where(status:3).size
+ @shixuns_type_check = MirrorRepository.pluck(:type_name,:id)
+ @params_page = params[:page] || 1
+ @shixuns = paginate shixuns.preload(:user,:challenges)
+
+ respond_to do |format|
+ format.js
+ format.html
+ format.xls{
+ filename = "实训详情_#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}.xls"
+ send_data(shixun_list_xls(shixuns), :type => 'application/octet-stream', :filename => filename_for_content_disposition(filename))
+ }
+ end
+ end
+
+ def destroy
+ Shixun.find(params[:id]).destroy!
+
+ render_delete_success
+ end
+
+ private
+ def shixun_list_xls shixuns
+ xls_report = StringIO.new
+ book = Spreadsheet::Workbook.new
+ sheet1 = book.create_worksheet :name => "sheet"
+ blue = Spreadsheet::Format.new :color => :blue, :weight => :bold, :size => 10
+ sheet1.row(0).default_format = blue
+ sheet1.row(0).concat(["实训ID","实训名称","技术平台", "Fork源", "实践任务","选择题任务","挑战人数", "通关人数", "状态","创建者", "单位", "职业", "关卡序号","关卡名称","技能标签"])
+ count_row = 1
+ shixuns.find_each do |shixun|
+ sheet1[count_row, 0] = shixun.identifier
+ sheet1[count_row, 1] = shixun.name
+ sheet1[count_row, 2] = shixun.shixun_main_name
+ sheet1[count_row, 3] = shixun.fork_identifier
+ sheet1[count_row, 4] = shixun.challenges.practice_type.count
+ sheet1[count_row, 5] = shixun.challenges.choose_type.count
+ sheet1[count_row, 6] = shixun.myshixuns.count
+ sheet1[count_row, 7] = shixun.myshixuns.finished.count
+ sheet1[count_row, 8] = shixun.shixun_status
+ sheet1[count_row, 9] = shixun.owner.show_real_name
+ sheet1[count_row, 10] = shixun.owner.school_name
+ sheet1[count_row, 11] = shixun.owner.identity
+ shixun.challenges.each do |challenge|
+ sheet1[count_row, 12] = "第#{challenge.position}关"
+ sheet1[count_row, 13] = challenge.subject
+ sheet1[count_row, 14] = challenge.tags_show
+ count_row += 1
+ end
+ count_row += 1
+ end
+ book.write xls_report
+ xls_report.string
+ end
+end
diff --git a/app/controllers/admins/video_applies_controller.rb b/app/controllers/admins/video_applies_controller.rb
new file mode 100644
index 000000000..2aef602a8
--- /dev/null
+++ b/app/controllers/admins/video_applies_controller.rb
@@ -0,0 +1,41 @@
+class Admins::VideoAppliesController < Admins::BaseController
+
+ def index
+ params[:status] ||= 'pending'
+ status = params[:status]
+ if status == 'all'
+ status = %w(agreed refused)
+ end
+
+ applies = VideoApply.where(status: status).order('video_applies.updated_at desc')
+
+ search = params[:keyword].to_s.strip
+ if search.present?
+ applies = applies.joins(:video)
+ .where('videos.title like :search', search: "%#{search}%")
+ end
+
+ @video_applies = paginate applies.includes(video: { user: :user_extension })
+ end
+
+ def agree
+ Videos::AgreeApplyService.new(current_video_apply, current_user).call
+ render_success_js
+ rescue Videos::AgreeApplyService::Error => e
+ render json: { status: -1, message: e.message }
+ end
+
+ def refuse
+ Videos::RefuseApplyService.new(current_video_apply, current_user, reason: params[:reason]).call
+ render_success_js
+ rescue Videos::RefuseApplyService::Error => e
+ render json: { status: -1, message: e.message }
+ end
+
+ private
+
+ def current_video_apply
+ @_current_video_apply ||= VideoApply.find(params[:id])
+ end
+end
+
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 177eb1a42..6046be5af 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -416,7 +416,7 @@ class ApplicationController < ActionController::Base
# 实训主类别列表,自带描述
def shixun_main_type
list = []
- mirrors = MirrorRepository.select([:id, :type_name]).published_main_mirror
+ mirrors = MirrorRepository.select([:id, :type_name, :description]).published_main_mirror
mirrors.try(:each) do |mirror|
list << {id: mirror.id, type_name: mirror.type_name, description: mirror.try(:description)}
end
@@ -426,9 +426,9 @@ class ApplicationController < ActionController::Base
# 小类别列表
def shixun_small_type
list = []
- mirrors = MirrorRepository.select([:id, :type_name]).published_small_mirror
+ mirrors = MirrorRepository.select([:id, :type_name, :description]).published_small_mirror
mirrors.try(:each) do |mirror|
- list << {id: mirror.id, type_name: mirror.type_name}
+ list << {id: mirror.id, type_name: mirror.type_name, description: mirror.description}
end
list
end
diff --git a/app/controllers/challenges_controller.rb b/app/controllers/challenges_controller.rb
index 0f6532372..8cb68b1d4 100644
--- a/app/controllers/challenges_controller.rb
+++ b/app/controllers/challenges_controller.rb
@@ -234,18 +234,21 @@ class ChallengesController < ApplicationController
# {...}, ...]
#}
def crud_answer
- raise '参考答案不能为空' if params[:challenge_answer].empty?
- raise '占比之和必须为100%' if params[:challenge_answer].map{|a| a[:score]}.sum != 100
- ActiveRecord::Base.transaction do
- @challenge.challenge_answers.destroy_all if @challenge.challenge_answers
- params[:challenge_answer].each_with_index do |answer, index|
- # 内容为空不保存
- next if answer[:contents].blank?
- ChallengeAnswer.create(name: answer[:name], contents: answer[:contents],
- level: index+1, score: answer[:score], challenge_id: @challenge.id)
+ if @challenge.challenge_answers && params[:challenge_answer].blank?
+ @challenge.challenge_answers.destroy_all
+ else
+ raise '参考答案不能为空' if params[:challenge_answer].empty?
+ raise '占比之和必须为100%' if params[:challenge_answer].map{|a| a[:score]}.sum != 100
+ ActiveRecord::Base.transaction do
+ @challenge.challenge_answers.destroy_all if @challenge.challenge_answers
+ params[:challenge_answer].each_with_index do |answer, index|
+ # 内容为空不保存
+ next if answer[:contents].blank?
+ ChallengeAnswer.create(name: answer[:name], contents: answer[:contents],
+ level: index+1, score: answer[:score], challenge_id: @challenge.id)
+ end
end
end
-
end
# 查看参考答案接口
diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb
new file mode 100644
index 000000000..66d327649
--- /dev/null
+++ b/app/controllers/colleges_controller.rb
@@ -0,0 +1,171 @@
+class CollegesController < ApplicationController
+ include Admins::PaginateHelper
+
+ layout 'college'
+
+ before_action :require_login
+ before_action :check_college_present!
+ before_action :check_manage_permission!
+
+ helper_method :current_school, :current_college
+
+ def statistics
+ # 教师、学生总数
+ count_statistic = UserExtension.where(school_id: current_school.id)
+ .select('SUM(IF(identity=0, 1, 0)) AS teachers_count, SUM(IF(identity=1, 1, 0)) AS students_count').first
+ @teachers_count = count_statistic['teachers_count']
+ @students_count = count_statistic['students_count']
+
+ # 课堂总数
+ @courses_count = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309).count
+ # 实训总数
+ @shixuns_count = Shixun.visible.joins('left join user_extensions on user_extensions.user_id = shixuns.user_id')
+ .where(user_extensions: { school_id: current_school.id }).count
+ end
+
+ def shixun_time
+ time_sum = Game.joins('left join user_extensions on user_extensions.user_id = games.user_id')
+ .where(user_extensions: { school_id: current_school.id }).sum(:cost_time)
+ shixun_time_sum = (time_sum / (24 * 60 * 60.0)).ceil
+
+ render json: { shixun_time: shixun_time_sum }
+ end
+
+ def shixun_report_count
+ shixun_report_count = StudentWork.where(work_status: [1, 2]).where('myshixun_id != 0')
+ .joins('left join user_extensions on user_extensions.user_id = student_works.user_id')
+ .where(user_extensions: { school_id: current_school.id }).count
+ render json: { shixun_report_count: shixun_report_count }
+ end
+
+ 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")
+ # ).order("publish_shixun_count desc, experience desc").limit(10)
+ @teachers =
+ @teachers.map do |teacher|
+ course_ids = Course.find_by_sql("SELECT 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 m.user_id=#{teacher.id} AND c.is_delete = 0 and c.school_id = #{current_school.id}")
+ course_count = course_ids.size
+ homeworks = HomeworkCommon.where(:homework_type => 4, :course_id => course_ids.map(&:id))
+ un_shixun_work_count = homeworks.where("publish_time > '#{Time.now}' or publish_time is null").count
+ shixun_work_count = homeworks.size - un_shixun_work_count
+ student_count = StudentsForCourse.where(:course_id => course_ids.map(&:id)).count
+ myshixun_ids = StudentWork.select("myshixun_id").where("homework_common_id in (#{homeworks.map(&:id).join(',').strip == "" ? -1 : homeworks.map(&:id).join(',')}) and myshixun_id is not null")
+ complete_myshixun = Myshixun.select("id").where(:status => 1, :id => myshixun_ids.map(&:myshixun_id)).size
+ all_myshixun = Myshixun.select("id").where(:id => myshixun_ids.map(&:myshixun_id)).size
+ complete_rate = all_myshixun == 0 ? 0 : ((complete_myshixun * 100) / all_myshixun).try(:round, 2).to_f
+ real_name = teacher.show_real_name
+ teacher = teacher.attributes.dup.merge({
+ real_name: real_name,
+ course_count: course_count,
+ shixun_work_count: shixun_work_count,
+ un_shixun_work_count: un_shixun_work_count,
+ student_count: student_count,
+ complete_rate: complete_rate
+ }).to_json
+ JSON.parse(teacher)
+ end
+ end
+
+ def shixun_chart_data
+ shixun_ids = HomeworkCommonsShixun.joins(homework_common: :course).where(courses: {school_id: current_school.id, is_delete: 0}).where('courses.id != 1309').pluck('distinct shixun_id')
+ shixun_count_map = ShixunTagRepertoire.joins(:tag_repertoire).where(shixun_id: shixun_ids).group('tag_repertoires.name').order('count_shixun_id desc').count(:shixun_id)
+
+ names = []
+ data = []
+ shixun_count_map.each do |name, count|
+ break if names.size == 9
+
+ names << name
+ data << { value: count, name: name }
+ end
+
+ if shixun_count_map.keys.size > 9
+ other_count = shixun_count_map.values[9..-1].reduce(:+)
+ names << 'Others'
+ data << { name: 'Others', value: other_count }
+ end
+
+ render json: { names: names, data: data }
+ end
+
+ # 在线课堂
+ def course_statistics
+ courses = Course.where(school_id: current_school.id, is_delete: 0).where.not(id: 1309)
+
+ courses = courses.left_joins(practice_homeworks: { student_works: { myshixun: :games } })
+ .select('courses.id, courses.name, courses.is_end, sum(games.evaluate_count) evaluating_count')
+ .group('courses.id').order('is_end asc, evaluating_count desc')
+
+ params[:per_page] = 8
+ @courses = paginate courses
+
+ course_ids = @courses.map(&:id)
+ @student_count = StudentsForCourse.where(course_id: course_ids).group(:course_id).count
+ @shixun_work_count = HomeworkCommon.where(homework_type: 4, course_id: course_ids).group(:course_id).count
+ @attachment_count = Attachment.where(container_id: course_ids, container_type: 'Course').group(:container_id).count
+ @message_count = Message.joins(:board).where(boards: { parent_id: 0, course_id: course_ids }).group('boards.course_id').count
+ @active_time = CourseActivity.where(course_id: course_ids).group(:course_id).maximum(:created_at)
+ @exercise_count = Exercise.where(course_id: course_ids).group(:course_id).count
+ @poll_count = Poll.where(course_id: course_ids).group(:course_id).count
+ @other_work_count = HomeworkCommon.where(homework_type: [1,3], course_id: course_ids).group(:course_id).count
+ end
+
+ # 学生实训
+ def student_shixun
+ @students = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id, identity: 1 }).includes(:user_extension).order('experience desc').limit(10)
+
+ student_ids = @students.map(&:id)
+ @shixun_count = Myshixun.where(user_id: student_ids).group(:user_id).count
+ @study_shixun_count = Myshixun.where(user_id: student_ids, status: 0).group(:user_id).count
+ end
+
+ def student_hot_evaluations
+ games = Game.joins(:myshixun).joins('join shixun_tag_repertoires str on str.shixun_id = myshixuns.shixun_id')
+ games = games.joins('join tag_repertoires tr on tr.id = str.tag_repertoire_id')
+ games = games.joins("join user_extensions ue on ue.user_id = myshixuns.user_id and ue.school_id = #{current_school.id}")
+ evaluate_count_map = games.group('tr.name').reorder('sum_games_evaluate_count desc').limit(10).sum('games.evaluate_count')
+
+ render json: { names: evaluate_count_map.keys, values: evaluate_count_map.values }
+ end
+
+ private
+
+ def require_login
+ return if User.current.logged?
+
+ redirect_to "/login?back_url=#{CGI::escape(request.fullpath)}"
+ end
+
+ def check_college_present!
+ return if current_college.present?
+
+ redirect_to '/404'
+ end
+
+ def check_manage_permission!
+ return if can_manage_college?
+
+ redirect_to '/403'
+ end
+
+ def can_manage_college?
+ return true if current_user.admin_or_business? # 超级管理员|运营
+ return true if current_college.is_a?(Department) && current_college.member?(current_user) # 部门管理员
+ return true if current_user.is_teacher? && current_user.school_id == current_school.id # 学校老师
+ return true if current_school.customer_id && current_user.partner&.partner_customers&.exists?(customer_id: current_school.customer_id)
+
+ false
+ end
+
+ def current_school
+ current_college.is_a?(School) ? current_college : current_college.school
+ end
+
+ def current_college
+ @_current_college ||= begin
+ Department.find_by(identifier: params[:id]) || School.find_by(id: params[:id])
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/controllers/concerns/admins/render_helper.rb b/app/controllers/concerns/admins/render_helper.rb
index 0ccc16a09..0f136b62d 100644
--- a/app/controllers/concerns/admins/render_helper.rb
+++ b/app/controllers/concerns/admins/render_helper.rb
@@ -1,36 +1,34 @@
module Admins::RenderHelper
extend ActiveSupport::Concern
+ def render_by_format(hash)
+ format = request.format.symbol
+ hash.key?(format) ? hash[format].call : hash[:html].call
+ end
+
def render_forbidden
- respond_to do |format|
- format.html { redirect_to '/403' }
- format.json { super }
- end
+ render_by_format(html: -> { current_user&.business? ? render('admins/shared/403') : redirect_to('/403') },
+ json: -> { render status: 403, json: { messages: I18n.t('error.forbidden') } } )
end
def render_not_found
- respond_to do |format|
- format.html { render 'admins/shared/404' }
- format.js { render_js_error('资源未找到') }
- format.json { render status: 404, json: { message: '资源未找到' } }
- end
+ render_by_format(html: -> { render 'admins/shared/404' },
+ js: -> { render_js_error('资源未找到') },
+ json: -> { render status: 404, json: { message: '资源未找到' } })
end
- def render_unprocessable_entity(message)
- respond_to do |format|
- format.html { render 'admins/shared/422' }
- format.js { render_js_error(message) }
- format.json { render status: 422, json: { message: message } }
- end
+ def render_unprocessable_entity(message, type: :alert)
+ render_by_format(html: -> { render 'admins/shared/422' },
+ js: -> { render_js_error(message, type: type) },
+ json: -> { render status: 422, json: { message: message } })
end
alias_method :render_error, :render_unprocessable_entity
- def internal_server_error
- respond_to do |format|
- format.html { render 'admins/shared/500' }
- format.js { render_js_error('系统错误') }
- format.json { render status: 500, json: { message: '系统错误' } }
- end
+ def internal_server_error(message = '系统错误')
+ @message = message
+ render_by_format(html: -> { render 'admins/shared/500' },
+ js: -> { render_js_error(message) },
+ json: -> { render status: 500, json: { message: message } })
end
def render_js_template(template, **opts)
@@ -42,7 +40,11 @@ module Admins::RenderHelper
end
alias_method :render_success_js, :render_delete_success
- def render_js_error(message)
- render_js_template 'admins/shared/error', locals: { message: message }
+ def render_js_error(message, type: :alert)
+ if type == :notify
+ render js: "$.notify({ message: '#{message}' },{ type: 'danger', delay: 5000 });"
+ else
+ render_js_template 'admins/shared/error', locals: { message: message }
+ end
end
end
\ No newline at end of file
diff --git a/app/controllers/concerns/git_common.rb b/app/controllers/concerns/git_common.rb
index 452204419..eab069b8e 100644
--- a/app/controllers/concerns/git_common.rb
+++ b/app/controllers/concerns/git_common.rb
@@ -10,7 +10,6 @@ module GitCommon
# ------------------------
# 版本库目录结构
def repository
- logger.info("ssssssseeeeeeee#{params}")
begin
@repo_url = repo_url @repo_path
@trees = GitService.file_tree(repo_path: @repo_path, path: @path)
@@ -44,4 +43,17 @@ module GitCommon
end
end
+ # 为版本库添加文件
+ def add_file
+ @path, message, content = params[:path].strip, params[:message], params[:content]
+ author_name, author_email = current_user.real_name, current_user.git_mail
+ Rails.logger.info(" good repo_name is #{@repo_path}")
+ @content = GitService.update_file(repo_path: @repo_path,
+ file_path: @path,
+ message: message.force_encoding('UTF-8'),
+ content: content.force_encoding('UTF-8'),
+ author_name: author_name,
+ author_email: author_email)
+ end
+
end
\ No newline at end of file
diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb
index e29fa8d7d..a26b1c23b 100644
--- a/app/controllers/courses_controller.rb
+++ b/app/controllers/courses_controller.rb
@@ -26,17 +26,19 @@ class CoursesController < ApplicationController
:base_info, :get_historical_courses, :create_group_by_importing_file,
:attahcment_category_list,:export_member_scores_excel, :duplicate_course,
:switch_to_teacher, :switch_to_assistant, :switch_to_student, :exit_course,
- :informs, :update_informs, :new_informs, :online_learning, :update_task_position, :tasks_list, :join_excellent_course]
+ :informs, :update_informs, :online_learning, :update_task_position, :tasks_list,
+ :join_excellent_course, :export_couser_info, :export_member_act_score, :new_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,
- :search_users, :add_students_by_search, :get_historical_courses, :add_teacher_popup, :add_teacher]
+ :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]
before_action :admin_allowed, only: [:set_invite_code_halt, :set_public_or_private, :change_course_admin,
:set_course_group, :create_group_by_importing_file, :update_informs, :new_informs,
:update_task_position, :tasks_list]
before_action :teacher_or_admin_allowed, only: [:graduation_group_list, :create_graduation_group, :join_graduation_group,
- :change_course_teacher, :export_member_scores_excel, :course_group_list,
+ :change_course_teacher, :course_group_list,
:teacher_application_review, :apply_teachers, :delete_course_teacher]
before_action :validate_course_name, only: [:create, :update]
before_action :find_board, only: :board_list
@@ -888,7 +890,7 @@ class CoursesController < ApplicationController
name = worksheet.cell(row, 1).to_s
if @course.course_groups.where(:name => name).blank?
- @course.course_groups << CourseGroup.new(:name => name)
+ @course.course_groups << CourseGroup.new(:name => name, :position => @course.course_groups_count + 1)
group_count += 1
end
end
@@ -1081,44 +1083,74 @@ class CoursesController < ApplicationController
@courses= @courses.page(@page).per(@page_size)
end
+ # 导出课堂信息
+ def export_couser_info
+ if params[:export].present? && params[:export]
+ normal_status(0,"正在下载中")
+ else
+ set_export_cookies
+ course_info_to_xlsx @course
+ filename_ = "#{current_user.real_name}_#{@course.name}_课堂信息_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
+ render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_course_info.xlsx.axlsx",
+ locals: {course_info: @course_info}
+ end
+ end
+
+ # 导出活跃度
+ def export_member_act_score
+ search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索
+ group_id = params[:group_id] #分班的班级id
+ @all_members = @course.students
+ @all_members = @all_members.where(course_group_id: group_id) unless group_id.blank?
+ unless search.blank?
+ @all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{search}%","%#{search}%")
+ end
+
+ if @all_members.size == 0
+ normal_status(-1,"课堂暂时没有学生")
+ elsif params[:export].present? && params[:export]
+ normal_status(0,"正在下载中")
+ else
+ set_export_cookies
+ @all_members = student_act_score group_id, search
+ act_score_to_xlsx(@all_members)
+ filename_ = "#{current_user.real_name}_#{@course.name}_活跃度_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
+ render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_act_score.xlsx.axlsx",
+ locals: {activity_level:@user_activity_level}
+ end
+ end
+
+ # 导出学生成绩
def export_member_scores_excel
ActiveRecord::Base.transaction do
begin
+ @all_members = @course.students
search = params[:search] ? "#{params[:search].strip}" : "" #用户名或学生学号id搜索
group_id = params[:group_id] #分班的班级id
- # if group_id && group_id != "0" && group_id != "-1"
- # @all_members = @course.students.course_find_by_ids("course_group_id",group_id)
- # elsif group_id && group_id == "0" # 未分班
- # @all_members = @course.course_members.ungroup_students
- # else
- # @all_members = @course.students
- # end
- # if name.present?
- # @all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{name}%","%#{name}%")
- # end
-
- @all_members = student_act_score group_id, search
+ @all_members = @all_members.where(course_group_id: group_id) unless group_id.blank?
+ unless search.blank?
+ @all_members = @all_members.joins(user: [:user_extension]).where('concat(users.lastname, users.firstname) like ? or user_extensions.student_id like ?',"%#{search}%","%#{search}%")
+ end
- @c_homeworks = @course.homework_commons.homework_published.order("homework_commons.publish_time asc, homework_commons.created_at asc")
- @c_exercises = @course.exercises.is_exercise_published.order("exercises.publish_time asc, exercises.created_at asc")
- # @c_polls = @course.polls.publish_or_not.order("polls.publish_time asc, polls.created_at asc")
- @c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
- if @user_course_identity > Course::ASSISTANT_PROFESSOR
- tip_exception(403,"无权限操作")
- elsif @all_members.size == 0
+ if @all_members.length == 0
normal_status(-1,"课堂暂时没有学生")
elsif params[:export].present? && params[:export]
- normal_status(0,"正在下载中")
+ normal_status(0,"正在下载中")
else
+ @c_homeworks = @course.homework_commons.homework_published.order("homework_commons.publish_time asc, homework_commons.created_at asc")
+ @c_exercises = @course.exercises.is_exercise_published.order("exercises.publish_time asc, exercises.created_at asc")
+ # @c_polls = @course.polls.publish_or_not.order("polls.publish_time asc, polls.created_at asc")
+ @c_tasks = @course.graduation_tasks.task_published.order("graduation_tasks.publish_time asc, graduation_tasks.created_at asc")
+
set_export_cookies
member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks)
- filename_ = "#{current_user.real_name}_#{@course.name}_全部成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
+ filename_ = "#{current_user.real_name}_#{@course.name}_总成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}"
render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx",
- locals: {course_info:@course_info, activity_level:@user_activity_level,
- course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,
+ locals: {course_scores:@course_user_scores,shixun_works:@shixun_work_arrays,
common_works:@common_work_arrays,group_works:@group_work_arrays,task_works:@task_work_arrays,
exercise_works:@exercise_work_arrays}
end
+
rescue Exception => e
uid_logger_error(e.message)
tip_exception(e.message)
@@ -1206,13 +1238,14 @@ class CoursesController < ApplicationController
tip_exception("开始时间不能为空") if params[:start_date].blank?
tip_exception("结束时间不能为空") if params[:end_date].blank?
tip_exception("结束时间必须晚于开始时间") if strf_date(params[:end_date]) <= strf_date(params[:start_date])
- tip_exception("开始时间和结束时间不能与往期开课时间重叠") if @course.nil? && @subject.max_course_end_date && strf_date(params[:start_date]) <= strf_date(@subject.max_course_end_date)
+ tip_exception("开始时间和结束时间不能早于往期开课时间") if @course.nil? && @subject.max_course_end_date && strf_date(params[:start_date]) <= strf_date(@subject.max_course_end_date)
validate_start_end_date if @course.present?
tip_exception("开放课堂必须包含公告栏和在线学习模块") unless params[:course_module_types].include?("announcement") && params[:course_module_types].include?("online_learning")
end
tip_exception("课堂所属单位不能为空!") if params[:school].blank?
tip_exception("请至少添加一个课堂模块") if params[:course_module_types].blank?
- @school = School.find_by!(name: params[:school].strip)
+ @school = School.find_by(name: params[:school].strip)
+ tip_exception("所属单位不存在") unless @school.present?
end
def validate_start_end_date
@@ -1291,13 +1324,7 @@ class CoursesController < ApplicationController
# end
def student_act_score group_id, search
- sql_select = %Q{SELECT cm.*,(
- SELECT SUM(student_works.work_score)
- FROM student_works,homework_commons
- WHERE student_works.homework_common_id = homework_commons.id
- AND homework_commons.course_id = #{@course.id}
- AND student_works.user_id = cm.user_id
- ) AS score,
+ sql_select = %Q{SELECT cm.*,
(SELECT max(student_id) FROM user_extensions WHERE user_extensions.user_id = cm.user_id) AS student_id,
(SELECT count(messages.id) FROM messages join boards on messages.board_id = boards.id WHERE boards.course_id = #{@course.id}
AND messages.author_id = cm.user_id and messages.parent_id is null) AS message_num,
@@ -1318,52 +1345,25 @@ class CoursesController < ApplicationController
FROM course_members cm}
if search.present? && group_id.present?
sql_select += %Q{ join users on cm.user_id = users.id
- joins user_extensions ue on ue.user_id = users.id
+ join user_extensions ue on ue.user_id = users.id
WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id} and
- (concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%') ORDER BY score desc}
+ (concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%')}
elsif search.present?
sql_select += %Q{ join users on cm.user_id = users.id
- joins user_extensions ue on ue.user_id = users.id
+ join user_extensions ue on ue.user_id = users.id
WHERE cm.role = 4 and
- (concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%') ORDER BY score desc}
+ (concat(users.lastname, users.firstname) like '%#{search}%' or ue.student_id like '%#{search}%')}
elsif group_id.present?
- sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id} ORDER BY score desc}
+ sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} and cm.course_group_id = #{group_id}}
else
- sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id} ORDER BY score desc}
+ sql_select += %Q{ WHERE cm.role = 4 and cm.course_id = #{@course.id}}
end
act_scores = CourseMember.find_by_sql(sql_select)
act_scores
end
- def member_to_xlsx(course,all_members,homeworks,exercises,tasks)
- #课堂的作业信息
- shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业
- 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
- end
-
- shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
-
- common_homeworks = homeworks.search_homework_type(1) #全部普通作业
- common_titles = common_homeworks.pluck(:name)+ ["总得分"]
- common_homeworks = common_homeworks&.includes(score_student_works: :user)
-
- group_homeworks = homeworks.search_homework_type(3) #全部分组作业
- group_titles = group_homeworks.pluck(:name)+ ["总得分"]
- group_homeworks = group_homeworks&.includes(score_student_works: :user)
-
- task_titles = tasks.pluck(:name) + ["总得分"]
- tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user)
-
- exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
- exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user)
-
- total_user_score_array = [] #学生总成绩集合
-
+ def course_info_to_xlsx course
#课堂信息
@course_info = []
course_info_title = "课堂信息概要"
@@ -1411,7 +1411,9 @@ class CoursesController < ApplicationController
end
course_group_info = [course_group_info_head,course_group_info_body]
@course_info += [course_info_title,course_main_info,course_group_info]
+ end
+ def act_score_to_xlsx all_members
#课堂活跃度
@user_activity_level = []
course_user_level = []
@@ -1426,8 +1428,6 @@ class CoursesController < ApplicationController
user_stu_id = u.student_id.present? ? (u.student_id.to_s + "\t") : "--"
user_school = user.school_name
user_course_group = u.course_group_name
- user_info_array = [user_login,user_name,user_mail,user_stu_id,user_school,user_course_group] #用户的信息集合
- user_work_scores = []
#课堂活跃度统计
user_homeworks_num = u.homework_num.to_i #完成的作业数
@@ -1446,23 +1446,69 @@ class CoursesController < ApplicationController
c_reply_num = user_reply_num
user_activity_levels = c_works_num + c_exercise_num + c_poll_num + c_file_num + c_message_num + c_reply_num + user_work_reply_num
user_ac_level = {
- u_1: user_name,
- u_2: user_login,
- u_2_1: user_mail,
- u_3: user_stu_id,
- u_4: user_school,
- u_5: user_course_group,
- u_6: c_works_num,
- u_7: c_exercise_num,
- u_8: c_poll_num,
- u_9: c_file_num,
- u_10: c_message_num,
- u_11: c_reply_num,
- u_12: user_work_reply_num,
- u_13: user_activity_levels
+ u_1: user_name,
+ u_2: user_login,
+ u_2_1: user_mail,
+ u_3: user_stu_id,
+ u_4: user_school,
+ u_5: user_course_group,
+ u_6: c_works_num,
+ u_7: c_exercise_num,
+ u_8: c_poll_num,
+ u_9: c_file_num,
+ u_10: c_message_num,
+ u_11: c_reply_num,
+ u_12: user_work_reply_num,
+ u_13: user_activity_levels
}
course_user_level.push(user_ac_level)
+ #.课堂活跃度统计的集合
+ course_user_level = course_user_level.sort_by {|k| k[:u_13]}.reverse
+ @user_activity_level = [course_activity_title,user_cell_head,course_user_level]
+ end
+ end
+
+ def member_to_xlsx(course,all_members,homeworks,exercises,tasks)
+ #课堂的作业信息
+ shixun_homeworks = homeworks.search_homework_type(4) #全部实训作业
+ 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
+ end
+
+ shixun_homeworks = shixun_homeworks&.includes(score_student_works: :user)
+
+ common_homeworks = homeworks.search_homework_type(1) #全部普通作业
+ common_titles = common_homeworks.pluck(:name)+ ["总得分"]
+ common_homeworks = common_homeworks&.includes(score_student_works: :user)
+
+ group_homeworks = homeworks.search_homework_type(3) #全部分组作业
+ group_titles = group_homeworks.pluck(:name)+ ["总得分"]
+ group_homeworks = group_homeworks&.includes(score_student_works: :user)
+
+ task_titles = tasks.pluck(:name) + ["总得分"]
+ tasks = tasks&.includes(user: :user_extension, score_graduation_works: :user)
+
+ exercise_titles = exercises.pluck(:exercise_name) + ["总得分"]
+ exercises = exercises&.includes(user: :user_extension, score_exercise_users: :user)
+
+ total_user_score_array = [] #学生总成绩集合
+
+ all_members.each do |u|
+ #用户的基本信息
+ user = u.user
+ user_login = user.login
+ user_name = user.real_name
+ user_mail = user.mail
+ user_stu_id = user.student_id.present? ? (user.student_id.to_s + "\t") : "--"
+ user_school = user.school_name
+ user_course_group = u.course_group_name
+ user_info_array = [user_name,user_login,user_mail,user_stu_id,user_school,user_course_group] #用户的信息集合
+ user_work_scores = []
+
#学生总成绩
shixun_score = 0.0 # 实训作业的总分
common_score = 0.0 #普通作业的总分
@@ -1560,10 +1606,6 @@ class CoursesController < ApplicationController
total_user_score_array.push(user_work_scores) # 全部成员的集合
end
- #1.课堂活跃度统计的集合
- course_user_level = course_user_level.sort_by {|k| k[:u_12]}.reverse
- @user_activity_level = [course_activity_title,user_cell_head,course_user_level]
-
#2.学生总成绩的集合
## 作业标题的集合
course_user_score_title = "学生总成绩"
diff --git a/app/controllers/exercise_bank_questions_controller.rb b/app/controllers/exercise_bank_questions_controller.rb
new file mode 100644
index 000000000..1fd8ad874
--- /dev/null
+++ b/app/controllers/exercise_bank_questions_controller.rb
@@ -0,0 +1,418 @@
+class ExerciseBankQuestionsController < ApplicationController
+ before_action :require_login, :check_auth #用户需登陆
+ before_action :get_exercise, only:[:create] #获取试卷
+ before_action :get_exercise_question, except: [:create] #获取试卷的问题及试卷
+ before_action :bank_admin #是否为老师
+ before_action :validate_params, only: [:create, :update] #传入参数的验证
+
+ def create
+ ActiveRecord::Base.transaction do
+ begin
+ question_options = {
+ :question_title => params[:question_title],
+ :question_type => params[:question_type].present? ? params[:question_type].to_i : 0, #默认为单选题
+ :question_number => @exercise.exercise_bank_questions.count + 1,
+ :question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0,
+ :shixun_id => params[:shixun_id].blank? ? "" : params[:shixun_id],
+ :is_ordered => params[:is_ordered] # 填空题的答案是否为一一对应关系,默认为true即为一一对应
+ }
+ @exercise_question = @exercise.exercise_bank_questions.new(question_options)
+ #插入问题时,那么从插入的这个id以后的question_num都将要+1
+ if params[:insert_id].present?
+ insert_exercise = @exercise.exercise_bank_questions.find_by(id: params[:insert_id])
+ if insert_exercise.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入
+ ques_num = insert_exercise.question_number.to_i
+ @exercise_question.question_number = ques_num + 1 #更新了问题的位置
+ @exercise.exercise_bank_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1")
+ end
+ end
+
+ if @exercise_question.save
+ #为选择题(包括单选和多选)的时候,创建问题选项
+ ques_type = @exercise_question.question_type
+ if ques_type <= Exercise::MULTIPLE
+ choices_array = params[:question_choices]
+ choices_count= choices_array.count
+ standard_answer = params[:standard_answers] #为数组格式,因为可能会有单选和多选,标准答案,已提前判断不能为空,
+ standard_answer = standard_answer.uniq.reject(&:blank?)
+ (1..choices_count).each do |c|
+ choice = choices_array[c-1] #每一个选项的内容
+ choice_option = {
+ :choice_position => c,
+ :choice_text => choice.strip
+ }
+ question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
+ question_choices.save
+ end
+ #标准答案的存储,如:["1","2","3"..]等,1对应A,2对应B,3对应C。。。
+ standard_answer.each do |a|
+ choice_id = a.to_i
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => choice_id #即为选择的位置参数
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ if standard_answer.count > 1 && ques_type == Exercise::SINGLE #当标准答案数大于1,且不为多选时,修改为多选
+ @exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
+ elsif standard_answer.count == 1 && ques_type == Exercise::MULTIPLE
+ @exercise_question.update_attribute("question_type",Exercise::SINGLE)
+ end
+ end
+ elsif ques_type == Exercise::JUDGMENT #这个为判断题
+ choices_array = params[:question_choices] #判断的选项,对/错等等
+ choices_count= choices_array.count
+ (1..choices_count).each do |c|
+ choice = choices_array[c-1] #每一个选项的内容
+ choice_option = {
+ :choice_position => c,
+ :choice_text => choice.strip
+ }
+ question_choices = @exercise_question.exercise_bank_choices.create(choice_option)
+ question_choices.save
+ end
+ standard_answer = params[:standard_answers] #对应选项的id
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => standard_answer.first.to_i
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ elsif ques_type == Exercise::COMPLETION #填空题,每空的参考答案有多个,那么以位置对应
+ standard_answer = params[:standard_answers]
+ standard_answer.each do |a|
+ null_choice_id = a[:choice_id]
+ null_choice_text = a[:answer_text]
+ null_choice_text.each do |n|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => null_choice_id,
+ :answer_text => n
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+ end
+ elsif ques_type == Exercise::SUBJECTIVE #简答题
+ if params[:standard_answers].present? && params[:standard_answers].reject(&:blank?).count > 0
+ standard_answer = params[:standard_answers]
+ standard_answer.each do |a|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :answer_text => a,
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+ end
+ elsif ques_type == Exercise::PRACTICAL #实训题
+ shixun = Shixun.find_by(id: params[:shixun_id])
+ shixun_scores = params[:question_scores] #试卷有多个的分值有多个分数表,所以为分数的数组
+ shixun_name = params[:shixun_name] || shixun.name
+ question_score = 0
+ shixun.challenges.try(:each_with_index) do |challenge,index|
+ shixun_option = {
+ :challenge_id => challenge.id,
+ :shixun_id => shixun.id,
+ :exercise_bank_question_id => @exercise_question.id,
+ :position => (index + 1),
+ :question_score => shixun_scores[index].present? ? shixun_scores[index].to_f.round(1) : 5
+ }
+ ex_shixun_challenge = ExerciseBankShixunChallenge.create(shixun_option)
+ question_score += ex_shixun_challenge.question_score # 问题的分数,为各个关卡分数的总和
+ end
+ @exercise_question.update_attributes(:question_score => question_score, :shixun_name=> shixun_name)
+ end
+ end
+ normal_status("创建成功")
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ raise ActiveRecord::Rollback
+ end
+ end
+ end
+
+ def update
+ ActiveRecord::Base.transaction do
+ begin
+ # 更新试卷题目的内容
+ question_options = {
+ :question_title => params[:question_title],
+ :is_ordered => params[:is_ordered], # 填空题的答案是否为一一对应关系,默认为true即为一一对应
+ :question_score => params[:question_score].present? ? params[:question_score].to_f.round(1) : 5.0 #不可修改分数
+ }
+ choices_array = params[:question_choices]
+ stan_answer_params = params[:standard_answers]
+ standard_answer = stan_answer_params.present? ? stan_answer_params.uniq.reject(&:blank?) : []
+ @exercise_question.update_attributes(question_options)
+ #当选项存在时,可修改选项内容,但是不能更改选项的位置(即不能增删选项)
+ if choices_array.present?
+ ex_choices = @exercise_question.exercise_bank_choices
+ ex_choice_count = ex_choices.count
+ choice_array_count = choices_array.count
+ ex_choice_count_array = (1..ex_choice_count).to_a
+ choice_array_count_array = (1..choice_array_count).to_a
+ if ex_choice_count > choice_array_count #如果选项有减少的,那么只更新传入的,删除以前的
+ choice_array_count_array.each do |c|
+ choice = choices_array[c-1] #每一个选项的内容
+ exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
+ exercise_choice.update(choice_text:choice)
+ end
+ drop_ex_choice = @exercise_question.exercise_bank_choices.left_choice_choose("choice_position",(choice_array_count))
+ drop_ex_choice.destroy_all
+ else
+ ex_choice_count_array.each do |c|
+ choice = choices_array[c-1] #每一个选项的内容
+ exercise_choice = @exercise_question.exercise_bank_choices.find_choice_custom("choice_position",(c))
+ exercise_choice.update(choice_text:choice)
+ end
+ new_add_choice = choice_array_count_array - ex_choice_count_array #新传入的需新增
+ if new_add_choice.count > 0
+ new_add_choice.each do |i|
+ choice_option = {
+ :choice_position => i,
+ :choice_text => choices_array[i-1].strip
+ }
+ question_choices = @exercise_question.exercise_bank_choices.new(choice_option)
+ question_choices.save
+ end
+ end
+ end
+ end
+ #试卷未发布时,当标准答案存在时,可修改标准答案内容,可增删标准答案,否则只能修改标准答案,不能增删标准答案
+ @exercise_answers_array = @exercise_question.exercise_bank_standard_answers #问卷的全部标准答案
+ if standard_answer.present?
+ if @exercise_question.question_type <= Exercise::JUDGMENT #选择题/判断题,标准答案为一个或多个
+ exercise_standard_choices = @exercise_answers_array.pluck(:exercise_bank_choice_id) #问题以前的全部标准答案选项位置
+ if exercise_standard_choices.sort != standard_answer.sort #表示答案有更改的
+ common_standard_choices = standard_answer & exercise_standard_choices # 传入的标准答案的选项位置和以前的并集,即表示不用做更改的
+ old_left_standard_choices = exercise_standard_choices - common_standard_choices # 以前的差集共同的,剩余的表示需要删掉
+ new_left_standard_choices = standard_answer - common_standard_choices # 传入的标准答案差集共同的,剩余的表示需要新建
+ if old_left_standard_choices.count > 0
+ @exercise_answers_array.standard_by_ids(old_left_standard_choices).destroy_all
+ end
+ if new_left_standard_choices.count > 0 #新建标准答案
+ new_left_standard_choices.each do |s|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => s.to_i #即为选择的位置参数
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+
+ end
+ if standard_answer.count > 1 && @exercise_question.question_type == Exercise::SINGLE #当标准答案数大于1,且不为多选时,修改为多选
+ @exercise_question.update_attribute("question_type",Exercise::MULTIPLE)
+ elsif standard_answer.count == 1 && @exercise_question.question_type == Exercise::MULTIPLE
+ @exercise_question.update_attribute("question_type",Exercise::SINGLE)
+ end
+ end
+ elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
+ old_ex_answer = @exercise_question.exercise_bank_standard_answers #当前问题的全部标准答案
+ old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).uniq.sort
+ new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.uniq.sort
+ if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
+ new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
+ old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_bank_choice_id).uniq #全部的答案数组序号
+ #删除多余的选项
+ if old_ex_answer_choice_ids.count > new_ex_answer_choice_ids.count #有减少的填空
+ delete_ex_answer_choice_ids = old_ex_answer_choice_ids - new_ex_answer_choice_ids
+ old_ex_answer.standard_by_ids(delete_ex_answer_choice_ids).destroy_all
+ end
+ standard_answer.each do |aa|
+ null_choice_id = aa[:choice_id]
+ null_choice_text = aa[:answer_text]
+ null_choice_text_count = null_choice_text.count #当前传入的答案数量
+ null_choice_text_count_array = (1..null_choice_text_count).to_a
+
+ ex_answer_pre = old_ex_answer.standard_by_ids(null_choice_id) #当前问题的全部答案
+ ex_answer_pre_count = ex_answer_pre.count
+ ex_answer_pre_count_array = (1..ex_answer_pre_count).to_a
+
+ if old_ex_answer_choice_ids.include?(null_choice_id) #以前的填空题答案包含有现在的填空序号
+ if null_choice_text_count >= ex_answer_pre_count
+ new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array
+ ex_answer_pre_count_array.each do |n|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => null_choice_id,
+ :answer_text => null_choice_text[n-1]
+ }
+ ex_answer_pre[n-1].update(standard_option)
+ end
+ if new_add_choice.count > 0 #表示有新增的
+ new_add_choice.each do |i|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => null_choice_id,
+ :answer_text => null_choice_text[i-1]
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+ end
+ else
+ new_delete_choice = ex_answer_pre_count_array - null_choice_text_count_array
+ null_choice_text.each_with_index do |n,index|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => null_choice_id,
+ :answer_text => n
+ }
+ ex_answer_pre[index].update(standard_option)
+ end
+ if new_delete_choice.count > 0 #表示填空题的答案有删减的
+ new_delete_choice.each do |d|
+ ex_answer_pre[d-1].destroy
+ end
+ end
+ end
+ else
+ null_choice_text.each do |n|
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :exercise_bank_choice_id => null_choice_id,
+ :answer_text => n
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+ end
+ end
+ end
+ end
+ end
+ if @exercise_question.question_type == Exercise::SUBJECTIVE #主观题
+ main_standard_answer = standard_answer.present? ? standard_answer.first : nil
+ if @exercise_answers_array.present?
+ @exercise_answers_array.first.update_attribute("answer_text",main_standard_answer)
+ else
+ standard_option = {
+ :exercise_bank_question_id => @exercise_question.id,
+ :answer_text => main_standard_answer,
+ }
+ question_standard_answer = ExerciseBankStandardAnswer.new(standard_option)
+ question_standard_answer.save
+ end
+ elsif @exercise_question.question_type == Exercise::PRACTICAL
+ question_score = 0
+ shixun_name = params[:shixun_name] || @exercise_question.shixun_name
+ @exercise_question.exercise_bank_shixun_challenges.each_with_index do |challenge, index|
+ challenge.question_score = params[:question_scores][index].to_f.round(1)
+ challenge.save
+ question_score += params[:question_scores][index].to_f.round(1)
+ end
+ @exercise_question.question_score = question_score
+ @exercise_question.shixun_name = shixun_name
+ @exercise_question.save
+ end
+ normal_status(0,"试卷更新成功")
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ raise ActiveRecord::Rollback
+ end
+ end
+ end
+
+ def up_down
+ ActiveRecord::Base.transaction do
+ begin
+ opr = params[:opr]
+ current_q_p = @exercise_question.question_number.to_i #问题的当前位置
+ if opr.present?
+ if opr.to_s == "up"
+ last_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p - 1)) # 当前问题的前一个问题
+ if last_q_p.present?
+ @exercise_question.update_attribute('question_number', (current_q_p - 1))
+ last_q_p.update_attribute('question_number', current_q_p) # 重新获取当前问题的位置
+ normal_status(0, "问题上移成功!")
+ else
+ normal_status(-1, "移动失败,已经是第一个问题了!")
+ end
+ elsif opr.to_s == "down"
+ next_q_p = @exercise.exercise_bank_questions.find_by(question_number: (current_q_p + 1)) # 当前问题的前一个问题
+ if next_q_p.present?
+ @exercise_question.update_attribute('question_number', (current_q_p + 1))
+ next_q_p.update_attribute('question_number', current_q_p)
+ normal_status(0, "问题下移成功!")
+ else
+ normal_status(-1, "移动失败,已经是最后一个问题了!")
+ end
+ end
+ else
+ normal_status(-1, "移动失败,请输入参数")
+ end
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+ end
+ end
+
+ #试卷问题的删除
+ def destroy
+ ActiveRecord::Base.transaction do
+ begin
+ question_d_id = @exercise_question.question_number.to_i #问题的当前位置
+ exercise_questions = @exercise.exercise_bank_questions
+ left_questions = exercise_questions.where("question_number > ?", question_d_id)
+ left_questions.update_all("question_number = question_number - 1") if left_questions
+ @exercise_question.destroy
+ normal_status(0, "删除成功")
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ end
+ end
+ end
+
+ private
+
+ def bank_admin
+ tip_exception(403, "无权限") unless @exercise.user_id == current_user.id || current_user.admin?
+ end
+
+ def get_exercise
+ @exercise = ExerciseBank.find_by!(id:params[:exercise_bank_id])
+ end
+
+ def get_exercise_question
+ @exercise_question = ExerciseBankQuestion.find_by!(id: params[:id])
+ @exercise = @exercise_question.exercise_bank
+ end
+
+ def validate_params
+ normal_status(-1,"题目不允许为空!") if (params[:question_title].blank? && params[:question_type].to_i != Exercise::PRACTICAL ) #除了实训题,其余题目必需有题干
+ normal_status(-1,"问题类型不允许为空!" ) if params[:question_type].blank?
+ normal_status(-1,"分值不允许为空!" ) if params[:question_score].blank? && params[:question_scores].blank? #分值的数组或参数必需存在一个
+ if params[:question_score].present? && params[:question_score].to_f <= 0.0 #问题类型存在,则分值不能为空,且必需大于0
+ normal_status(-1,"分值必需大于0!")
+ elsif (params[:question_score].present? && params[:question_score].to_f.round(1) > 100.0) || (params[:question_scores].present? && (params[:question_scores].map{|a| a.to_f.round(1)}.max > 100.0))
+ normal_status(-1,"分值不能超过100分!")
+ elsif params[:question_scores].present? && params[:question_scores].include?(0.0) #如果有负数,则自动取绝对值,#多个分数值,针对实训题的
+ normal_status(-1,"分值必需大于0!")
+ elsif params[:standard_answers].present? && params[:question_choices].present? && (params[:standard_answers].count > params[:question_choices].count)
+ normal_status(-1,"标准答案数不能大于选项数!")
+ elsif [0,1,2,3].include?(params[:question_type].to_i) && (params[:standard_answers].blank? || params[:standard_answers].include?("")) #选择题/判断题/填空题 问题选项/标准答案不能为空,也不能包含空的内容
+ normal_status(-1,"标准答案不能为空!")
+ elsif params[:question_type].to_i == 2 && (params[:standard_answers].count > 1 || params[:question_choices].blank? || params[:question_choices].include?("")) #判断题的标准答案不能大于1个,选项不能为空
+ normal_status(-1,"判断题选项不能为空/标准答案不能大于1个!")
+ elsif params[:question_type].to_i <= 1 && (params[:question_choices].blank? || params[:question_choices].include?("") || params[:question_choices].count < 2) #选择题选项不能为空,且不能小于2
+ normal_status(-1,"选择题选项内容不能为空,且不能少于2个!")
+ elsif params[:question_type].to_i == 3 && (params[:standard_answers].blank? || params[:standard_answers].count > 5 ) #填空题选项最多为5个,且如果为1个的话,不允许修改is_ordered
+ normal_status(-1,"填空题标准答案不能为空/不能超过5个!")
+ elsif params[:question_type].to_i == 4 && params[:standard_answers].count > 2 #简单题参考答案最多为1个
+ normal_status(-1,"简答题的参考答案不能大于2个!")
+ elsif params[:question_type].to_i == 5
+ if params[:shixun_id].blank? #实训题的id不能为空
+ normal_status(-1,"实训题id不能为空!")
+ elsif params[:shixun_name].blank?
+ normal_status(-1,"实训题名称不能为空!")
+ end
+ end
+ end
+
+end
diff --git a/app/controllers/exercise_banks_controller.rb b/app/controllers/exercise_banks_controller.rb
new file mode 100644
index 000000000..dafaf131e
--- /dev/null
+++ b/app/controllers/exercise_banks_controller.rb
@@ -0,0 +1,129 @@
+#encoding: UTF-8
+class ExerciseBanksController < ApplicationController
+ before_action :require_login
+ before_action :find_bank, except: [:choose_shixun]
+ before_action :bank_admin, only: [:update]
+ before_action :commit_shixun_present, only: [:commit_shixun]
+
+ def show
+ @exercise_questions = @bank.exercise_bank_questions&.includes(:exercise_bank_choices, :exercise_bank_shixun_challenges,
+ :exercise_bank_standard_answers).order("question_number ASC")
+
+ if @bank.container_type == "Exercise"
+ get_exercise_question_count
+ else
+ get_poll_question_count
+ end
+ end
+
+ def update
+ tip_exception("标题不能为空!") if params[:exercise_name].blank?
+ @bank.update_attributes!(name: params[:exercise_name], description: params[:exercise_description])
+ normal_status(0,"更新成功")
+ end
+
+ def choose_shixun
+ search = params[:search]
+ type = params[:type]
+ # 超级管理员用户显示所有未隐藏的实训、非管理员显示所有已发布的实训(对本单位公开且未隐藏未关闭)
+ if current_user.admin?
+ @shixuns = Shixun.unhidden
+ else
+ none_shixun_ids = ShixunSchool.where("school_id != #{current_user.school_id}").pluck(:shixun_id)
+
+ @shixuns = Shixun.where.not(id: none_shixun_ids).unhidden
+ end
+
+ # 实训的所有标签
+ @tags = TagRepertoire.select([:id, :name]).joins(:shixuns).where(shixuns: {id: @shixuns}).distinct
+
+ if params[:search] && params[:search].strip != ""
+ @shixuns = @shixuns.joins(:user).where("shixuns.name like ? or concat(users.lastname, users.firstname) like ?",
+ "%#{search}%", "%#{search}%").distinct
+ end
+
+ unless type.blank? || type == "all"
+ @shixuns = @shixuns.joins(:shixun_tag_repertoires).where(shixun_tag_repertoires: {tag_repertoire_id: type}).distinct
+ end
+
+ @shixuns = @shixuns.select([:id, :name, :status, :myshixuns_count, :identifier, :user_id, :trainee])
+ @total_count = @shixuns.size
+
+ ## 分页参数
+ page = params[:page] || 1
+ @shixuns = @shixuns.reorder("shixuns.created_at desc").includes(:challenges, user: [user_extension: :school]).page(page).per(10)
+ end
+
+ #确认实训的选择
+ def commit_shixun
+ @shixun_challenges = @shixun.challenges
+ @shixun_challenges_count = @shixun_challenges.size
+ end
+
+ private
+
+ 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
+ tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
+ end
+
+ #判断实训是否已选择
+ def commit_shixun_present
+ question_shixun_ids = @exercise.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)
+ normal_status(-1,"该实训已选择!")
+ elsif @shixun.blank?
+ normal_status(-1,"该实训不存在!")
+ end
+ end
+
+ def get_exercise_question_count
+ @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_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_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_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_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_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_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 #主观题
+ end
+
+end
diff --git a/app/controllers/exercise_questions_controller.rb b/app/controllers/exercise_questions_controller.rb
index e6f17778a..57116a9e5 100644
--- a/app/controllers/exercise_questions_controller.rb
+++ b/app/controllers/exercise_questions_controller.rb
@@ -255,8 +255,8 @@ class ExerciseQuestionsController < ApplicationController
end
elsif @exercise_question.question_type == Exercise::COMPLETION #填空题
old_ex_answer = @exercise_question.exercise_standard_answers #当前问题的全部标准答案
- old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).uniq.sort
- new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.uniq.sort
+ old_ex_answer_choice_texts = old_ex_answer.pluck(:answer_text).sort
+ new_ex_answer_choice_texts = standard_answer.pluck(:answer_text).sum.sort
if old_ex_answer_choice_texts != new_ex_answer_choice_texts #填空题标准答案有更改时,才会更新标准答案
new_ex_answer_choice_ids = standard_answer.map {|a| a[:choice_id]}.uniq #新传入的答案数组序号
old_ex_answer_choice_ids = old_ex_answer.pluck(:exercise_choice_id).uniq #全部的答案数组序号
@@ -280,11 +280,12 @@ class ExerciseQuestionsController < ApplicationController
if null_choice_text_count >= ex_answer_pre_count
new_add_choice = null_choice_text_count_array - ex_answer_pre_count_array
ex_answer_pre_count_array.each do |n|
- standard_option = {
- :exercise_question_id => @exercise_question.id,
- :exercise_choice_id => null_choice_id,
- :answer_text => null_choice_text[n-1]
+ @hash_symbol_null_ = {
+ :exercise_question_id => @exercise_question.id,
+ :exercise_choice_id => null_choice_id,
+ :answer_text => null_choice_text[n - 1]
}
+ standard_option = @hash_symbol_null_
ex_answer_pre[n-1].update(standard_option)
end
if new_add_choice.count > 0 #表示有新增的
@@ -680,8 +681,9 @@ class ExerciseQuestionsController < ApplicationController
normal_status(-1,"已发布/已截止,不允许增删答案!")
elsif standard_answer.present?
if @exercise_question.question_type == Exercise::COMPLETION
- exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq
- unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count)
+ # exercise_answers_text = standard_answer.map{|a| a[:answer_text]}.sum.uniq
+ # unless (standard_answer.count == exercise_choice_ids.count) && (standard_answers_text.count == exercise_answers_text.count)
+ unless standard_answer.count == exercise_choice_ids.count
normal_status(-1,"已发布/已截止,不允许增删标准答案!")
end
elsif @exercise_question.question_type == Exercise::SUBJECTIVE
diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb
index a916f5351..791d145c2 100644
--- a/app/controllers/files_controller.rb
+++ b/app/controllers/files_controller.rb
@@ -171,17 +171,18 @@ class FilesController < ApplicationController
begin
attachment_ids.each do |attachment_id|
ori = Attachment.find_by_id(attachment_id)
- @course.attachments.each do |att|
- @exist = false
- if att.id == ori.id || (!att.copy_from.nil? && !ori.copy_from.nil? && att.copy_from == ori.copy_from) || att.copy_from == ori.id || att.id == ori.copy_from
- att.created_on = Time.now
- att.save
- @exist = true
- break
- end
- end
-
- next if @exist
+ # 同一个资源可以多次发送到课堂
+ # @course.attachments.each do |att|
+ # @exist = false
+ # if att.id == ori.id || (!att.copy_from.nil? && !ori.copy_from.nil? && att.copy_from == ori.copy_from) || att.copy_from == ori.id || att.id == ori.copy_from
+ # att.created_on = Time.now
+ # att.save
+ # @exist = true
+ # break
+ # end
+ # end
+ #
+ # next if @exist
attach_copied_obj = ori.copy
attach_copied_obj.container = @course
attach_copied_obj.created_on = Time.now
diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb
index 0064914d3..89b6dca27 100644
--- a/app/controllers/games_controller.rb
+++ b/app/controllers/games_controller.rb
@@ -392,59 +392,6 @@ class GamesController < ApplicationController
end
end
- # # 文件更新;数据评测记录
- # # 生成重新评测认证码
- # # content_modified:0 表示文件没有更新;content_modified:1 表示文件有更新
- # def file_update
- # path = params[:path].strip unless params[:path].blank?
- # myshixun = @game.myshixun
- # rev = params[:rev] ? params[:rev] : "master"
- # @content_modified = 0
- # # params[:evaluate] 实训评测时更新必须给的参数,需要依据该参数做性能统计,其它类型的更新可以跳过
- # # 自动保存的时候evaluate为0;点评测的时候为1
- # if params[:evaluate] == 1
- # record = EvaluateRecord.create!(:user_id => current_user.id, :shixun_id => myshixun.shixun_id, :game_id => @game.id)
- # uid_logger("-- game is #{@game.id}, record id is #{record.id}, time is **** #{Time.now.strftime("%Y-%m-%d %H:%M:%S.%L")}")
- # student_work_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f
- # record.update_attributes!(:student_work => student_work_time)
- # end
- # # 远程版本库文件内容
- # last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"]
- # last_content = tran_base64_decode64(last_content)
- #
- # content = if @myshixun.mirror_name.select{|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present?
- # params[:content].gsub(/\t/, ' ')
- # else
- # params[:content]
- # end
- # if content != last_content
- # @content_modified = 1
- # code_file = @g.edit_file(myshixun.gpid, current_user.login, :content => content, :file_path => path,
- # :branch_name => rev, :commit_message => params[:evaluate] == 0 ? "auto commit" : "task commit")
- # uid_logger("-- file update #{code_file}")
- # # REDO:更新失败的处理
- # raise("文件更新失败") unless code_file
- # end
- #
- # if record.present?
- # consume_time = format("%.3f", (Time.now.to_f - record.created_at.to_f)).to_f
- # record.update_attributes!(:file_update => consume_time)
- # end
- #
- # # status为2说明是重新评测
- # if @game.status == 2
- # code = CODES.sample(8).join
- # @resubmit = "#{code}_#{@myshixun.id}"
- # end
- #
- # if content != last_content && code_file.blank?
- # raise("实训平台繁忙(繁忙等级:81),请稍后刷新并重试")
- # end
- # rescue Exception => e
- # uid_logger("-- file update failed #{e.message}")
- # raise Educoder::TipException.new("#{e.message}")
- # end
-
# 恢复初始代码
# 注意path为当前打开文件的path
def reset_original_code
diff --git a/app/controllers/graduation_works_controller.rb b/app/controllers/graduation_works_controller.rb
index a4a59a3f5..204e0e5d4 100644
--- a/app/controllers/graduation_works_controller.rb
+++ b/app/controllers/graduation_works_controller.rb
@@ -274,7 +274,7 @@ class GraduationWorksController < ApplicationController
@is_author = @work.user_id == current_user.id
@work_members = @task.task_type == 1 ? [] : @task.graduation_works.where.not(user_id: @work.user_id).
where(group_id: @work.group_id).includes(:user)
- @attachments = @work.attachments.where.not(attachtype: 7)
+ @attachments = @work.attachments.where("attachtype != 7 or attachtype is null")
end
def comment_list
diff --git a/app/controllers/gtopic_banks_controller.rb b/app/controllers/gtopic_banks_controller.rb
new file mode 100644
index 000000000..291302bc2
--- /dev/null
+++ b/app/controllers/gtopic_banks_controller.rb
@@ -0,0 +1,40 @@
+class GtopicBanksController < ApplicationController
+ before_action :require_login
+ before_action :find_bank
+ before_action :bank_admin, only: [:edit, :update]
+
+ def show
+ @bank_attachments = @bank.attachments
+ end
+
+ def edit
+ @attachments = @bank.attachments
+ end
+
+ def update
+ ActiveRecord::Base.transaction do
+ @bank.update_attributes(gtopic_bank_params)
+ Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
+ normal_status(0, "更新成功")
+ end
+ end
+
+ private
+
+ 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
+ tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
+ end
+
+ def gtopic_bank_params
+ tip_exception("name参数不能为空") if params[:gtopic_bank][:name].blank?
+ tip_exception("description参数不能为空") if params[:gtopic_bank][:description].blank?
+ params.require(:gtopic_bank).permit(:name, :topic_type, :topic_source, :topic_property_first, :description,
+ :topic_property_second, :source_unit, :topic_repeat, :province, :city)
+ end
+end
diff --git a/app/controllers/homework_banks_controller.rb b/app/controllers/homework_banks_controller.rb
new file mode 100644
index 000000000..7e10509ba
--- /dev/null
+++ b/app/controllers/homework_banks_controller.rb
@@ -0,0 +1,69 @@
+class HomeworkBanksController < ApplicationController
+ before_action :require_login
+ before_action :find_bank
+ before_action :bank_params, only: [:update]
+ before_action :bank_admin, only: [:update, :destroy, :set_public]
+
+ def show
+ @bank_attachments = @bank.attachments.where(attachtype: 1)
+ @reference_attachments = @bank.attachments.where(attachtype: 2)
+ end
+
+ def update
+ ActiveRecord::Base.transaction do
+ if @bank.homework_type == 1
+ @bank.update_attributes(name: params[:name], description: params[:description], reference_answer: params[:reference_answer])
+ elsif @bank.homework_type == 3
+ @bank.update_attributes(name: params[:name], description: params[:description], reference_answer: params[:reference_answer],
+ base_on_project: params[:base_on_project], min_num: params[:min_num], max_num: params[:max_num])
+ end
+
+ # 作业描述的附件
+ Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
+ # 作业参考答案的附件
+ Attachment.associate_container(params[:reference_attachment_ids], @bank.id, @bank.class, 2) if params[:reference_attachment_ids]
+
+ normal_status(0, "更新成功")
+ end
+ end
+
+ def destroy
+ ActiveRecord::Base.transaction do
+ @bank.homework_commons.update_all(homework_bank_id: nil)
+ @bank.destroy!
+ normal_status("删除成功")
+ end
+ end
+
+ def set_public
+ @bank.update_attributes(is_public: 1)
+ normal_status("更新成功")
+ end
+
+ private
+
+ 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
+ tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
+ end
+
+ def bank_params
+ tip_exception("name参数不能为空") if params[:homework_bank][:name].blank?
+ 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("最小人数不能小于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
+ params.require(:homework_bank).permit(:name, :description, :reference_answer) if @bank.homework_type == 1
+ params.require(:homework_bank).permit(:name, :description, :reference_answer, :min_num, :max_num, :base_on_project) if @bank.homework_type == 3
+ end
+
+end
diff --git a/app/controllers/poll_bank_questions_controller.rb b/app/controllers/poll_bank_questions_controller.rb
new file mode 100644
index 000000000..71f302115
--- /dev/null
+++ b/app/controllers/poll_bank_questions_controller.rb
@@ -0,0 +1,158 @@
+class PollBankQuestionsController < ApplicationController
+ before_action :require_login, :check_auth #用户需登陆
+ before_action :get_poll, only:[:create] #获取试卷
+ before_action :get_poll_question, except: [:create] #获取试卷的问题及试卷
+ before_action :bank_admin #是否为老师
+ before_action :validates_params, only: [:create, :update] #传入参数的验证
+
+ def create
+ ActiveRecord::Base.transaction do
+ begin
+ poll_options = {
+ :question_title => params[:question_title],
+ :question_type => params[:question_type],
+ :is_necessary => params[:is_necessary].to_i,
+ :question_number => @poll.exercise_bank_questions.count + 1,
+ :max_choices => params[:max_choices] || nil,
+ :min_choices => params[:min_choices] || nil
+ }
+ @poll_question = @poll.exercise_bank_questions.new(poll_options)
+
+ if params[:insert_id].present? #插入问题时,那么从插入的这个id以后的question_num都将要+1
+ insert_poll = @poll.exercise_bank_questions.find_by(id: params[:insert_id])
+ if insert_poll.present? #如果该问题存在的话,意思是如果是第一题,那么就不存在插入
+ ques_num = insert_poll.question_number.to_i
+ @poll_question.question_number = ques_num + 1 #更新了问题的位置
+ @poll.exercise_bank_questions.insert_question_ex(ques_num).update_all("question_number = question_number + 1")
+ end
+ end
+ if @poll_question.save!
+ if params[:question_type] != 3
+ p_answer = params[:question_answers]
+ p_other_answer = params[:question_other_answer]
+ # 新增选择题答案选择的选项
+ (1..p_answer.count).each do |i|
+ answer = p_answer[i-1] # 传入的答案的内容
+ question_option = {
+ :choice_position => i,
+ :choice_text => answer
+ }
+ poll_answers = @poll_question.exercise_bank_choices.new question_option
+ poll_answers.save
+ end
+ # 新增答案的其他选项
+ if p_other_answer
+ question_option = {
+ :choice_position => p_answer.count + 1,
+ :choice_text => ''
+ }
+ poll_answers = @poll_question.exercise_bank_choices.new question_option
+ poll_answers.save
+ end
+ end
+ end
+ normal_status("创建成功")
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ raise ActiveRecord::Rollback
+ end
+ end
+ end
+
+ def update
+ ActiveRecord::Base.transaction do
+ begin
+ if @poll_question.question_type < 3 #当为单选题或多选题时
+ p_answer = params[:question_answers]
+ p_other_answer = params[:question_other_answer]
+ p_answer_count = p_answer.count
+ @poll_current_answers = @poll_question.exercise_bank_choices.count
+ @poll_question.exercise_bank_choices.each do |an|
+ if (p_answer_count < @poll_current_answers) && (p_answer_count..@poll_current_answers).to_a.include?(an.choice_position)
+ an.destroy
+ end
+ end
+ (1..p_answer_count).each do |i|
+ answer = @poll_question.exercise_bank_choices.find_choice_custom("choice_position",i).first
+ if answer # 判断该位置的answer是否存在,存在则更新.不存在则跳到下一步
+ answer.choice_text = p_answer[i-1]
+ answer.choice_position = i
+ answer.save
+ else
+ answer_options = {
+ :choice_position => i,
+ :choice_text => p_answer[i-1]
+ }
+ @poll_question.exercise_bank_choices.new answer_options
+ end
+ end
+ if p_other_answer #判断答案的其他选项是否存在
+ other_answer = @poll_question.exercise_bank_choices.find_choice_custom("choice_text","").first
+ if other_answer.blank?
+ question_option = {
+ :choice_position => p_answer_count + 1,
+ :choice_text => ''
+ }
+ @poll_question.exercise_bank_choices.new question_option
+ else
+ other_answer.choice_position = p_answer_count + 1
+ other_answer.save
+ end
+ end
+ end
+ @poll_question.update_attributes(poll_questions_params)
+ normal_status("问卷更新成功")
+ rescue Exception => e
+ uid_logger_error(e.message)
+ tip_exception(e.message)
+ raise ActiveRecord::Rollback
+ end
+ end
+ end
+
+ private
+
+ def bank_admin
+ tip_exception(403, "无权限") unless @poll.user_id == current_user.id || current_user.admin?
+ end
+
+ def get_poll
+ @poll = ExerciseBank.find_by!(id: params[:exercise_bank_id])
+ end
+
+ def get_poll_question
+ @poll_question = ExerciseBankQuestion.find_by!(id: params[:id])
+ @poll = @poll_question.exercise_bank
+ end
+
+ def poll_questions_params
+ params.permit(:question_title,:question_type,:is_necessary,:question_number,:max_choices,:min_choices)
+ end
+
+ def validates_params
+ tip_exception(-1, "问题标题不能为空!") if params[:question_title].blank?
+ tip_exception(-1, "是否要求必答的值不能为空!") if params[:is_necessary].blank?
+ tip_exception(-1, "问题类型不能为空!") if params[:question_type].blank?
+ if params[:min_choices].present? && params[:max_choices].present? && (params[:min_choices].to_i > params[:max_choices].to_i)
+ tip_exception(-1, "最小可选不能大于最大可选!")
+ elsif params[:question_answers].present? && (params[:max_choices].to_i > params[:question_answers].count)
+ tip_exception(-1, "选择题的最大可选项不能大于答案数!")
+ elsif [1,3].include?(params[:question_type]) && (params[:max_choices].to_i > 0 || params[:min_choices].to_i > 0)
+ tip_exception(-1, "单选题或主观题不能有最大或最小选择数!")
+ elsif params[:question_type] == 3 && (params[:question_answers] || params[:question_other_answer])
+ tip_exception(-1, "主观问题不需要可选答案!")
+ elsif params[:question_type] != 3
+ if params[:question_answers].present? && params[:question_answers].include?("")
+ tip_exception(-1, "选择题不能有空值!")
+ elsif params[:question_other_answer].present? && params[:question_other_answer].length > 0
+ tip_exception(-1, "其他选项不能有值!")
+ elsif params[:question_type] == 1 && params[:question_answers].count < 2
+ tip_exception(-1, "单选题选项不能小于2!")
+ elsif params[:question_type] == 2 && params[:question_answers].count < 3
+ tip_exception(-1, "多选题选项不能小于3!")
+ end
+ end
+ end
+
+end
diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb
index 0f301dd4f..bc549cf1d 100644
--- a/app/controllers/polls_controller.rb
+++ b/app/controllers/polls_controller.rb
@@ -901,9 +901,9 @@ class PollsController < ApplicationController
error_question = []
@poll_multi_questions.each do |q|
poll_user_votes = current_user.poll_votes.where(poll_question_id:q.id)&.size
- if q.max_choices.present? && (poll_user_votes > q.max_choices)
+ if q.max_choices.present? && (q.max_choices > 0) && (poll_user_votes > q.max_choices)
error_messages = "第#{q.question_number}题:超过最大选项限制"
- elsif q.min_choices.present? && (poll_user_votes < q.min_choices)
+ elsif q.min_choices.present? && (q.min_choices > 0)&& (poll_user_votes < q.min_choices)
error_messages = "第#{q.question_number}题:不得少于最小选项限制"
else
error_messages = nil
@@ -936,7 +936,7 @@ class PollsController < ApplicationController
def commit_result
ActiveRecord::Base.transaction do
begin
- @poll_users = @poll.all_poll_users(current_user.id)
+ @poll_users = @poll.all_poll_users(current_user.id).where(commit_status:1) # 问卷已提交的用户
@poll_commit_ids = @poll_users.commit_by_status(1).pluck(:user_id) #问卷提交用户的id
@page = params[:page] || 1
@limit = params[:limit] || 10
diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb
index 098c07d1b..f09a53dbe 100644
--- a/app/controllers/question_banks_controller.rb
+++ b/app/controllers/question_banks_controller.rb
@@ -1,6 +1,7 @@
class QuestionBanksController < ApplicationController
before_action :require_login, :check_auth
- before_action :params_filter
+ before_action :params_filter, except: [:my_courses]
+ # before_action :teacher_or_admin, except: [:bank_list]
# 题库选用列表
# object_type: # normal 普通作业题库; group 分组作业题库; poll问卷题库; exercise试卷题库; gtask 毕设选题题库;gtopic 毕设任务
@@ -79,10 +80,39 @@ class QuestionBanksController < ApplicationController
end
end
+ def my_courses
+ @courses = current_user.manage_courses.where(is_delete: 0, is_end: 0)
+ unless params[:search].blank?
+ @courses = @courses.where("name like ?", "%#{params[:search].strip}%")
+ end
+ end
+
+ def send_to_course
+ banks = object_banks
+ course = current_user.manage_courses.find_by!(id: params[:course_id])
+ banks.each do |bank|
+ case @object_type
+ when 'HomeworkBank' # 作业
+ quote_homework_bank bank, course
+ when 'ExerciseBank'
+ if bank.container_type == 'Exercise' # 试卷
+ quote_exercise_bank bank, course
+ else # 问卷
+ quote_poll_bank bank, course
+ end
+ when 'GtaskBank'
+ quote_gtask_bank bank, course
+ when 'GtopicBank'
+ quote_gtopic_bank bank, course
+ end
+ end
+ normal_status("发送成功")
+ end
+
def destroy
bank = current_bank
- unless user.admin? || bank.user_id == user.id
+ unless current_user.admin? || bank.user_id == current_user.id
render_forbidden
return
end
@@ -97,11 +127,32 @@ class QuestionBanksController < ApplicationController
render_ok
end
+ def multi_delete
+ @objects = object_banks
+ @objects.destroy_all
+ normal_status("删除成功")
+ end
+
+ def multi_public
+ @objects = object_banks
+ @objects.update_all(is_public: true)
+ normal_status("更新成功")
+ end
+
private
+ def object_banks
+ banks ||= @object_type.classify.constantize.where(@object_filter).where(id: params[:object_id])
+ unless current_user.admin?
+ banks = banks.where(user_id: current_user.id)
+ end
+ banks
+ end
+
def current_bank
@_current_bank ||= @object_type.classify.constantize.where(@object_filter).find(params[:id])
end
+
def params_filter
type = ["normal", "group", "poll", "exercise", "gtask", "gtopic"]
tip_exception("object_type类型不正确") unless type.include?(params[:object_type])
@@ -128,6 +179,10 @@ class QuestionBanksController < ApplicationController
end
end
+ def teacher_or_admin
+ tip_exception(403, "无权限操作") unless current_user.is_certification_teacher || current_user.admin?
+ end
+
def quote_homework_bank homework, course
ActiveRecord::Base.transaction do
# 复制作业的基本信息
diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb
index d9ab31b8d..8591f9821 100644
--- a/app/controllers/shixuns_controller.rb
+++ b/app/controllers/shixuns_controller.rb
@@ -6,15 +6,18 @@ class ShixunsController < ApplicationController
:discusses, :collaborators, :fork_list, :propaedeutics]
before_action :check_account, only: [:new, :create, :shixun_exec]
+ before_action :find_shixun, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
+ :propaedeutics, :departments, :apply_shixun_mirror,
+ :get_mirror_script, :download_file]
- before_action :find_shixun, :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
- :propaedeutics, :departments, :apply_shixun_mirror,
- :get_mirror_script, :download_file]
- before_action :find_repo_name, only: [:repository, :commits, :file_content, :update_file, :shixun_exec, :copy]
+ before_action :shixun_access_allowed, except: [:index, :new, :create, :menus, :get_recommend_shixuns,
+ :propaedeutics, :departments, :apply_shixun_mirror,
+ :get_mirror_script, :download_file]
+ 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,
:shixun_members_added, :change_manager, :collaborators_delete,
- :cancel_publish, :add_collaborators]
+ :cancel_publish, :add_collaborators, :add_file]
before_action :portion_allowed, only: [:copy]
before_action :special_allowed, only: [:send_to_course, :search_user_courses]
@@ -348,7 +351,8 @@ class ShixunsController < ApplicationController
sub_type.each do |mirror|
ShixunMirrorRepository.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
# 实训子镜像服务配置
- ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror)
+ name = MirrorRepository.find_by(id: mirror).try(:name) #查看镜像是否有名称,如果没有名称就不用服务配置
+ ShixunServiceConfig.create!(:shixun_id => @shixun.id, :mirror_repository_id => mirror) if name.present?
end
end
@@ -422,7 +426,12 @@ class ShixunsController < ApplicationController
# 超级管理员和运营人员才能保存 中间层服务器pod信息的配置
if current_user.admin? || current_user.business?
@shixun.shixun_service_configs.destroy_all
- @shixun.shixun_service_configs.create!(service_config_params[:shixun_service_configs])
+ 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
rescue Exception => e
uid_logger_error(e.message)
diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb
index b4677f4e3..519bb7e7d 100644
--- a/app/controllers/student_works_controller.rb
+++ b/app/controllers/student_works_controller.rb
@@ -92,6 +92,7 @@ class StudentWorksController < ApplicationController
student_work.commit_time = Time.now
student_work.update_time = Time.now
student_work.commit_user_id = current_user.id
+ student_work.update_user_id = current_user.id
student_work.group_id = @homework.homework_type == "group" ? @homework.max_group_id : 0
#提交作品时,计算是否迟交
@@ -112,7 +113,7 @@ class StudentWorksController < ApplicationController
homework_common_id: @homework.id, project_id: student_work.project_id,
late_penalty: student_work.late_penalty, work_status: student_work.work_status,
commit_time: Time.now, update_time: Time.now, group_id: student_work.group_id,
- commit_user_id: current_user.id)
+ commit_user_id: current_user.id, update_user_id: current_user.id)
stu_work.save!
student_work.attachments.each do |attachment|
att = attachment.copy
@@ -156,6 +157,7 @@ class StudentWorksController < ApplicationController
begin
@work.description = params[:description]
@work.update_time = Time.now
+ @work.update_user_id = current_user.id
# @work.commit_user_id = current_user.id
if @work.save!
Attachment.associate_container(params[:attachment_ids], @work.id, @work.class)
@@ -172,7 +174,7 @@ class StudentWorksController < ApplicationController
# 原成员更新描述、更新时间以及附件
@homework.student_works.where(group_id: @work.group_id, user_id: (work_user_ids & params_user_ids)).each do |work|
# work.update_attributes(update_time: Time.now, description: @work.description, commit_user_id: current_user.id)
- work.update_attributes(update_time: Time.now, description: @work.description)
+ work.update_attributes(update_time: Time.now, description: @work.description, update_user_id: current_user.id)
work.attachments.destroy_all
@work.attachments.each do |attachment|
att = attachment.copy
@@ -192,7 +194,7 @@ class StudentWorksController < ApplicationController
@homework.student_works.where(group_id: @work.group_id, user_id: delete_user_ids).
update_all(work_status: 0, description: nil, late_penalty: 0, commit_time: nil, update_time: nil,
final_score: nil, teacher_score: nil, student_score: nil, teaching_asistant_score: nil,
- work_score: nil, project_id: 0, group_id: 0, commit_user_id: nil)
+ work_score: nil, project_id: 0, group_id: 0, commit_user_id: nil, update_user_id: nil)
# 新增加的成员
(params_user_ids - work_user_ids).each do |user_id|
@@ -200,7 +202,7 @@ class StudentWorksController < ApplicationController
stu_work.update_attributes(user_id: user_id, description: @work.description, homework_common_id: @homework.id,
project_id: @work.project_id, late_penalty: @work.late_penalty,
work_status: @work.work_status, commit_time: Time.now, update_time: Time.now,
- group_id: @work.group_id, commit_user_id: @work.commit_user_id)
+ group_id: @work.group_id, commit_user_id: @work.commit_user_id, update_user_id: current_user.id)
@work.attachments.each do |attachment|
att = attachment.copy
att.author_id = attachment.author_id
@@ -653,15 +655,15 @@ class StudentWorksController < ApplicationController
# 查重作品调分
def adjust_review_score
tip_exception("缺少type参数") if params[:type].blank? || !["review", "report"].include?(params[:type])
- if params[:type] == "review" && (params[:score].nil? || params[:challenge_id].nil? || params[:code_rate].nil? || params[:copy_user_id].nil?)
+ if params[:type] == "review" && (params[:score].blank? || params[:challenge_id].blank? || params[:code_rate].blank? || params[:copy_user_id].blank?)
tip_exception("参数错误,score和challenge_id和code_rate和copy_user_id不能为空")
- elsif params[:type] == "report" && (params[:score].nil? || params[:challenge_id].nil?)
- tip_exception("参数错误,score和challenge_id")
+ elsif params[:type] == "report" && (params[:score].blank? || params[:challenge_id].blank?)
+ tip_exception("参数错误,score和challenge_id不能为空")
end
challenge_setting = @homework.homework_challenge_settings.find_by(challenge_id: params[:challenge_id])
challenge = challenge_setting&.challenge
- tip_exception("不能小于零") if params[:score] < 0
- tip_exception("不能大于关卡分值:#{challenge_setting.score}分") if challenge_setting.score < params[:score]
+ tip_exception("不能小于零") if params[:score].to_i < 0
+ tip_exception("不能大于关卡分值:#{challenge_setting.score}分") if challenge_setting.score < params[:score].to_i
ActiveRecord::Base.transaction do
begin
diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb
index 5b926ee48..d97b7172c 100644
--- a/app/controllers/subjects_controller.rb
+++ b/app/controllers/subjects_controller.rb
@@ -270,7 +270,7 @@ class SubjectsController < ApplicationController
page = params[:page] || 1
member_ids = @subject.subject_members.map(&:user_id).join(',')
condition = "%#{params[:search].strip}%".gsub(" ","")
- @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, firstname, login, mail)) LIKE ?", member_ids, "#{condition}")
+ @users = User.where("id not in (?) and status = 1 and LOWER(concat(lastname, ifnull(firstname, ''), login)) LIKE ?", member_ids, "#{condition}")
@users = @users.page(page).per(10)
@users = @users.includes(:user_extension)
@@ -450,7 +450,7 @@ class SubjectsController < ApplicationController
@time = 0
@user_tags = []
else
- pass_challenge_ids = pass_games.map(&:challenge_id)
+ pass_challenge_ids = pass_games.map(&:challenge_id).uniq # 按道理是不用去重的,但是历史数据与重复
subject_challenge_count = @subject.shixuns.sum(:challenges_count)
# 用户通关获得的标签
@user_tags = ChallengeTag.where(challenge_id: pass_challenge_ids).pluck(:name)
diff --git a/app/controllers/task_banks_controller.rb b/app/controllers/task_banks_controller.rb
new file mode 100644
index 000000000..e2e7f0a1a
--- /dev/null
+++ b/app/controllers/task_banks_controller.rb
@@ -0,0 +1,49 @@
+class TaskBanksController < ApplicationController
+ before_action :require_login
+ before_action :find_bank
+ before_action :bank_admin, only: [:update]
+
+ def show
+ @bank_attachments = @bank.attachments
+ end
+
+ def update
+ ActiveRecord::Base.transaction do
+ begin
+ @bank.update_attributes(gtask_bank_params)
+ Attachment.associate_container(params[:attachment_ids], @bank.id, @bank.class) if params[:attachment_ids]
+ normal_status(0, "更新成功")
+ rescue Exception => e
+ uid_logger(e.message)
+ tip_exception(e.message)
+ raise ActiveRecord::Rollback
+ end
+ end
+ end
+
+ private
+
+ 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
+ tip_exception(403, "无权限") unless @bank.user_id == current_user.id || current_user.admin?
+ end
+
+ 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
+ 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
+ end
+end
diff --git a/app/controllers/users/question_banks_controller.rb b/app/controllers/users/question_banks_controller.rb
index 0dc4a3f3f..d2f111973 100644
--- a/app/controllers/users/question_banks_controller.rb
+++ b/app/controllers/users/question_banks_controller.rb
@@ -1,4 +1,5 @@
class Users::QuestionBanksController < Users::BaseController
+ before_action :require_login
before_action :check_query_params!
before_action :check_user_permission!
@@ -8,7 +9,7 @@ class Users::QuestionBanksController < Users::BaseController
@count = question_banks.count
@course_lists = service.course_lists
- @question_banks = paginate(question_banks.includes(:user, :course_list), special: true)
+ @question_banks = paginate(question_banks.includes(:user, :course_list))
load_question_banks_solve_count # for solve n + 1
end
@@ -18,8 +19,8 @@ class Users::QuestionBanksController < Users::BaseController
def load_question_banks_solve_count
question_bank_ids = @question_banks.map(&:id)
@solve_count_map =
- case params[:category]
- when 'common', 'group' then
+ case params[:object_type]
+ when 'normal', 'group' then
StudentWork.where(is_delete: false, work_status: [1, 2, 3]).joins(:homework_common)
.where(homework_commons: { homework_bank_id: question_bank_ids })
.group('homework_commons.homework_bank_id').count
@@ -36,20 +37,20 @@ class Users::QuestionBanksController < Users::BaseController
.group('graduation_tasks.gtask_bank_id').count
when 'gtopic' then
StudentGraduationTopic.joins(:graduation_topic)
- .where(gtopic_banks: { gtopic_bank_id: question_bank_ids }).where('status != 0')
- .group('gtopic_banks.gtopic_bank_id').count
+ .where(graduation_topics: { gtopic_bank_id: question_bank_ids }).where('student_graduation_topics.status = 1')
+ .group('graduation_topics.gtopic_bank_id').count
end
end
def query_params
- params.permit(:type, :category, :course_list_id, :sort_by, :sort_direction)
+ params.permit(:type, :object_type, :course_list_id, :sort_by, :sort_direction)
end
def check_query_params!
params[:type] = 'personal' if params[:type].blank? || !%w(personal publicly).include?(params[:type])
- if params[:category].blank? || !%w(common group exercise poll gtask gtopic).include?(params[:category])
- params[:category] = 'common'
+ if params[:object_type].blank? || !%w(normal group exercise poll gtask gtopic).include?(params[:object_type])
+ params[:object_type] = 'normal'
end
if params[:sort_by].blank? || !%w(updated_at name contributor).include?(params[:sort_by])
@@ -62,12 +63,10 @@ class Users::QuestionBanksController < Users::BaseController
end
def check_user_permission!
- return if User.current.admin? || (observed_logged_user? && read_question_bank_permission?)
-
- render_forbidden
- end
-
- def read_question_bank_permission?
- params[:type] == 'personal' ? User.current.is_teacher? : User.current.certification_teacher?
+ if params[:type] == 'publicly'
+ render_error("未通过职业认证") unless User.current.admin? || User.current.certification_teacher?
+ else
+ render_forbidden unless User.current.admin? || User.current.is_teacher?
+ end
end
end
\ No newline at end of file
diff --git a/app/helpers/admins/mirror_repositories_helper.rb b/app/helpers/admins/mirror_repositories_helper.rb
new file mode 100644
index 000000000..d62494e24
--- /dev/null
+++ b/app/helpers/admins/mirror_repositories_helper.rb
@@ -0,0 +1,23 @@
+module Admins::MirrorRepositoriesHelper
+ def mirror_type_tag(mirror)
+ case mirror.main_type
+ when '1' then ' '.html_safe
+ when '0' then ' '.html_safe
+ end
+ end
+
+ def mirror_status_tag(mirror)
+ case mirror.status
+ when 0
+ ' '.html_safe
+ when 1
+ ' '.html_safe
+ when 2, 3
+ ' '.html_safe
+ when 4
+ ' '.html_safe
+ when 5
+ ' '.html_safe
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/helpers/exercise_bank_questions_helper.rb b/app/helpers/exercise_bank_questions_helper.rb
new file mode 100644
index 000000000..10df0f5b3
--- /dev/null
+++ b/app/helpers/exercise_bank_questions_helper.rb
@@ -0,0 +1,2 @@
+module ExerciseBankQuestionsHelper
+end
diff --git a/app/helpers/homework_banks_helper.rb b/app/helpers/homework_banks_helper.rb
new file mode 100644
index 000000000..805479c79
--- /dev/null
+++ b/app/helpers/homework_banks_helper.rb
@@ -0,0 +1,2 @@
+module HomeworkBanksHelper
+end
diff --git a/app/helpers/homework_commons_helper.rb b/app/helpers/homework_commons_helper.rb
index fa563a72c..a3ed43405 100644
--- a/app/helpers/homework_commons_helper.rb
+++ b/app/helpers/homework_commons_helper.rb
@@ -48,7 +48,7 @@ module HomeworkCommonsHelper
end
when 2, 5, 6
status << "评阅中"
- time = "评阅剩余时间:" + (course.end_date.present? ? how_much_time(course.end_date.end_of_day) : "")
+ time = course.end_date.present? ? ("评阅剩余时间:" + how_much_time(course.end_date.end_of_day)) : ""
time_status = 5
end
diff --git a/app/helpers/shixuns_helper.rb b/app/helpers/shixuns_helper.rb
index d849053ca..b41750bed 100644
--- a/app/helpers/shixuns_helper.rb
+++ b/app/helpers/shixuns_helper.rb
@@ -14,6 +14,19 @@ module ShixunsHelper
%W(未发布 已发布 已关闭)[status-1]
end
+ def shixun_authentication_status shixun
+ case shixun.try(:status)
+ when 0,nil
+ "编辑中"
+ when 1
+ "待审核"
+ when 2
+ "已发布"
+ when 3
+ "已关闭"
+ end
+ end
+
# 已完成实训所获得的经验值
def myshixun_exp myshixun
score = 0
diff --git a/app/jobs/delete_department_notify_job.rb b/app/jobs/delete_department_notify_job.rb
new file mode 100644
index 000000000..1da5e2e85
--- /dev/null
+++ b/app/jobs/delete_department_notify_job.rb
@@ -0,0 +1,21 @@
+# 删除部门 消息通知
+class DeleteDepartmentNotifyJob < ApplicationJob
+ queue_as :notify
+
+ def perform(department_id, operator_id, user_ids)
+ department = Department.unscoped.find_by(id: department_id)
+ return if department.blank? || user_ids.blank?
+
+ attrs = %i[ user_id trigger_user_id container_id container_type tiding_type status created_at updated_at]
+
+ same_attrs = {
+ trigger_user_id: operator_id, container_id: department.id, container_type: 'Department',
+ status: 4, tiding_type: 'System'
+ }
+ Tiding.bulk_insert(*attrs) do |worker|
+ user_ids.each do |user_id|
+ worker.add same_attrs.merge(user_id: user_id)
+ end
+ end
+ end
+end
diff --git a/app/models/challenge.rb b/app/models/challenge.rb
index 8087fd6ab..455fd1b6a 100644
--- a/app/models/challenge.rb
+++ b/app/models/challenge.rb
@@ -95,6 +95,14 @@ class Challenge < ApplicationRecord
end
end
+ def tags_show
+ if self.challenge_tags.nil?
+ "--"
+ else
+ self.try(:challenge_tags).map(&:name).join(";")
+ end
+ end
+
## 选择题答案
def choose_answer
result = []
diff --git a/app/models/customer.rb b/app/models/customer.rb
new file mode 100644
index 000000000..3baf32738
--- /dev/null
+++ b/app/models/customer.rb
@@ -0,0 +1,10 @@
+class Customer < ApplicationRecord
+ default_scope { order(created_at: :desc) }
+
+ belongs_to :school
+
+ has_many :partner_customers, dependent: :destroy
+ has_many :partners, through: :partner_customers
+
+ has_many :users
+end
\ No newline at end of file
diff --git a/app/models/department.rb b/app/models/department.rb
index 9c4a0908b..3b0672cce 100644
--- a/app/models/department.rb
+++ b/app/models/department.rb
@@ -2,6 +2,18 @@ class Department < ApplicationRecord
belongs_to :school
has_many :department_members, dependent: :destroy
+ has_many :member_users, through: :department_members, source: :user
+
+ has_many :user_extensions, dependent: :nullify
+ has_many :apply_add_departments
scope :without_deleted, -> { where(is_delete: false) }
+
+ def member?(user)
+ department_members.exists?(user_id: user.id)
+ end
+
+ def soft_delete!
+ update!(is_delete: true)
+ end
end
diff --git a/app/models/exercise_bank.rb b/app/models/exercise_bank.rb
index 22c2a5041..067d080b5 100644
--- a/app/models/exercise_bank.rb
+++ b/app/models/exercise_bank.rb
@@ -18,4 +18,7 @@ class ExerciseBank < ApplicationRecord
scope :exercise_bank_search, lambda { |keywords|
where("name LIKE ?", "%#{keywords}%") unless keywords.blank?}
+ validates :name, length: { maximum: 60, too_long: "60 characters is the maximum allowed" }
+ validates :description, length: { maximum: 100, too_long: "100 characters is the maximum allowed" }
+
end
\ No newline at end of file
diff --git a/app/models/exercise_bank_choice.rb b/app/models/exercise_bank_choice.rb
index d3a91bb02..be29ca786 100644
--- a/app/models/exercise_bank_choice.rb
+++ b/app/models/exercise_bank_choice.rb
@@ -1,4 +1,7 @@
class ExerciseBankChoice < ApplicationRecord
belongs_to :exercise_bank_question
has_many :exercise_bank_standard_answers
+
+ scope :find_choice_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
+ scope :left_choice_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
end
\ No newline at end of file
diff --git a/app/models/exercise_bank_question.rb b/app/models/exercise_bank_question.rb
index 5a39fd5d2..fdd343f5a 100644
--- a/app/models/exercise_bank_question.rb
+++ b/app/models/exercise_bank_question.rb
@@ -1,17 +1,24 @@
class ExerciseBankQuestion < ApplicationRecord
belongs_to :exercise_bank
- belongs_to :shixun
+ belongs_to :shixun, optional: true
has_many :exercise_bank_shixun_challenges,:dependent => :destroy
has_many :exercise_bank_choices, :dependent => :destroy
has_many :exercise_bank_standard_answers, :dependent => :destroy
#attr_accessible :question_number, :question_score, :question_title, :question_type
+ scope :insert_question_ex, lambda {|k| where("question_number > ?",k)}
+ scope :find_by_custom, lambda {|k,v| where("#{k} = ?",v)} #根据传入的参数查找问题
+ scope :left_question_choose, lambda {|k,v| where("#{k} > ?",v)} #根据传入的参数查找问题
+ scope :find_objective_questions, -> {where("question_type != ?",4)} #查找全部客观题
+
def question_type_name
case self.question_type
- when 1
+ when 0
"单选题"
- when 2
+ when 1
"多选题"
+ when 2
+ "判断题"
when 3
"填空题"
when 4
@@ -20,4 +27,14 @@ class ExerciseBankQuestion < ApplicationRecord
"实训题"
end
end
+
+
+ #获取问题的全部标准答案
+ def get_standard_answer_ids
+ exercise_bank_standard_answers.pluck(:exercise_bank_choice_id)
+ end
+
+ def get_standard_answer_text
+ exercise_bank_standard_answers.pluck(:answer_text)
+ end
end
\ No newline at end of file
diff --git a/app/models/exercise_bank_standard_answer.rb b/app/models/exercise_bank_standard_answer.rb
index 9cd82afe6..2535473b0 100644
--- a/app/models/exercise_bank_standard_answer.rb
+++ b/app/models/exercise_bank_standard_answer.rb
@@ -2,4 +2,5 @@ class ExerciseBankStandardAnswer < ApplicationRecord
belongs_to :exercise_bank_question
belongs_to :exercise_bank_choice
#attr_accessible :answer_text
+ scope :standard_by_ids, lambda { |s| where(exercise_bank_choice_id: s) }
end
\ No newline at end of file
diff --git a/app/models/homework_common.rb b/app/models/homework_common.rb
index ac11a54b7..c33bbca0d 100644
--- a/app/models/homework_common.rb
+++ b/app/models/homework_common.rb
@@ -3,7 +3,7 @@ class HomeworkCommon < ApplicationRecord
enum homework_type: { normal: 1, program: 2, group: 3, practice: 4 }, _suffix: true
has_many :homework_group_settings, dependent: :destroy
has_many :published_settings, -> { group_published }, class_name: "HomeworkGroupSetting"
- has_many :student_works, -> { where("is_delete = 0") }
+ has_many :student_works, -> { where(is_delete: 0) }
has_many :score_student_works, -> { where("is_delete = 0 and work_status != 0").order("work_score desc") }, class_name: "StudentWork"
has_one :homework_detail_manual, dependent: :destroy
diff --git a/app/models/library_apply.rb b/app/models/library_apply.rb
index 0a7ec8aec..85944169b 100644
--- a/app/models/library_apply.rb
+++ b/app/models/library_apply.rb
@@ -16,4 +16,8 @@ class LibraryApply < ApplicationRecord
transitions from: :pending, to: :agreed
end
end
+
+ def status_i18n
+
+ end
end
\ No newline at end of file
diff --git a/app/models/mirror_operation_record.rb b/app/models/mirror_operation_record.rb
new file mode 100644
index 000000000..39e352a0f
--- /dev/null
+++ b/app/models/mirror_operation_record.rb
@@ -0,0 +1,7 @@
+# status: 0 创建镜像; 1 修改镜像ID; 2 修改镜像name 3 删除镜像 4.从主节点同步镜像到子节点(子节点发生异常), 5. 修改镜像别名, 6. 修改镜像的状态
+# user_id: -1时,证明是非人为因素造成,中间层异常导致
+class MirrorOperationRecord < ActiveRecord::Base
+ default_scope { order(created_at: :desc) }
+
+ belongs_to :mirror_repository
+end
diff --git a/app/models/mirror_repository.rb b/app/models/mirror_repository.rb
index be26b5ad1..e29b008ad 100644
--- a/app/models/mirror_repository.rb
+++ b/app/models/mirror_repository.rb
@@ -8,4 +8,8 @@ class MirrorRepository < ApplicationRecord
scope :published_mirror, -> { where(status: 1) }
scope :published_main_mirror, -> { published_mirror.where(main_type: 1) }
scope :published_small_mirror, -> { published_mirror.where(main_type: 0) }
+
+ def deletable?
+ status != 1 && !shixun_mirror_repositories.exists?
+ end
end
diff --git a/app/models/myshixun.rb b/app/models/myshixun.rb
index 80074df6e..006bbf26d 100644
--- a/app/models/myshixun.rb
+++ b/app/models/myshixun.rb
@@ -7,6 +7,9 @@ class Myshixun < ApplicationRecord
belongs_to :user
belongs_to :shixun, counter_cache: true
+ has_one :last_executable_task, -> { where(status: [0, 1]).reorder(created_at: :asc) }, class_name: 'Game'
+ has_one :last_task, -> { all }, class_name: 'Game'
+
validates_uniqueness_of :shixun_id, :scope => :user_id, :message => "shixun_id and user_id unique error"
scope :finished, lambda { where(status: 1) }
scope :search_myshixun_user, ->(user_id){where(user_id:user_id)}
diff --git a/app/models/partner.rb b/app/models/partner.rb
index f2f8cca2a..9bff82028 100644
--- a/app/models/partner.rb
+++ b/app/models/partner.rb
@@ -1,3 +1,5 @@
class Partner < ApplicationRecord
+ belongs_to :school, optional: true
+
has_many :users
end
diff --git a/app/models/partner_customer.rb b/app/models/partner_customer.rb
new file mode 100644
index 000000000..b3f4e567b
--- /dev/null
+++ b/app/models/partner_customer.rb
@@ -0,0 +1,4 @@
+class PartnerCustomer < ApplicationRecord
+ belongs_to :partner
+ belongs_to :customer
+end
\ No newline at end of file
diff --git a/app/models/school.rb b/app/models/school.rb
index 8a28ae4bf..1034fd997 100644
--- a/app/models/school.rb
+++ b/app/models/school.rb
@@ -13,6 +13,9 @@ class School < ApplicationRecord
has_many :school_daily_reports, dependent: :destroy
has_many :courses
+ has_many :customers, dependent: :destroy
+ has_many :partners, dependent: :destroy
+
# 学校管理员
def manager?(user)
ec_school_users.exists?(user_id: user.id)
diff --git a/app/models/shixun.rb b/app/models/shixun.rb
index d61ba45b9..db6bca43e 100644
--- a/app/models/shixun.rb
+++ b/app/models/shixun.rb
@@ -78,6 +78,29 @@ class Shixun < ApplicationRecord
shixun_info.try(:evaluate_script)
end
+ def fork_identifier
+ self.fork_from.nil? ? "--" : Shixun.where(id: self.fork_from).first.try(:identifier)
+ end
+
+ def shixun_status
+ status = ""
+ case self.status
+ when 0
+ status = "编辑中"
+ when 1
+ status = "审核中"
+ when 2
+ status = "已发布"
+ when 3
+ status = "已关闭"
+ end
+ status
+ end
+
+ def is_tag_used?(id)
+ tag_repertoires.map(&:id).include?(id)
+ end
+
# 实训用户tag
def user_tags_name(user = User.current)
Shixun.joins(challenges: [:challenge_tags, :games]).where(games: {status: 2, user_id: user.id}, shixuns: {id:id})
@@ -133,6 +156,10 @@ class Shixun < ApplicationRecord
User.find(self.user_id)
end
+ def shixun_main_name
+ self.mirror_repositories.published_main_mirror.first.try(:type_name)
+ end
+
def is_published?
status > 1
end
diff --git a/app/models/student_work.rb b/app/models/student_work.rb
index 074068273..168cfeb68 100644
--- a/app/models/student_work.rb
+++ b/app/models/student_work.rb
@@ -2,6 +2,7 @@ class StudentWork < ApplicationRecord
#学生提交作品表 #work_status :0 未提交 1 已提交 2 迟交
belongs_to :user
belongs_to :commit_user, class_name: 'User', foreign_key: :commit_user_id, optional: true
+ belongs_to :update_user, class_name: 'User', foreign_key: :update_user_id, optional: true
belongs_to :homework_common
belongs_to :myshixun, optional: true
has_many :student_works_evaluation_distributions, dependent: :destroy
diff --git a/app/models/user.rb b/app/models/user.rb
index 5ba8667f5..12759ea4d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -139,7 +139,7 @@ class User < ApplicationRecord
has_many :videos, dependent: :destroy
# 客户管理
- belongs_to :partner
+ belongs_to :partner, optional: true
# Groups and active users
scope :active, lambda { where(status: STATUS_ACTIVE) }
diff --git a/app/queries/admins/department_query.rb b/app/queries/admins/department_query.rb
new file mode 100644
index 000000000..f0b8c5d24
--- /dev/null
+++ b/app/queries/admins/department_query.rb
@@ -0,0 +1,32 @@
+class Admins::DepartmentQuery < 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
+ departments = Department.where(is_auth: true).without_deleted
+
+ keyword = params[:keyword].to_s.strip
+ if keyword.present?
+ departments = departments.joins(:school)
+ .where('schools.name LIKE :keyword OR departments.name LIKE :keyword', keyword: "%#{keyword}%")
+ end
+
+ if params[:with_member].to_s == 'true'
+ subquery = DepartmentMember.where('department_id = departments.id').select('1 AS one').to_sql
+ departments = departments.where("EXISTS(#{subquery})")
+ end
+
+ if params[:with_identifier].to_s == 'true'
+ departments = departments.where.not(identifier: nil).where.not(identifier: '')
+ end
+
+ custom_sort(departments, params[:sort_by], params[:sort_direction])
+ end
+end
\ No newline at end of file
diff --git a/app/queries/admins/library_apply_query.rb b/app/queries/admins/library_apply_query.rb
new file mode 100644
index 000000000..9fdc2d067
--- /dev/null
+++ b/app/queries/admins/library_apply_query.rb
@@ -0,0 +1,29 @@
+class Admins::LibraryApplyQuery < ApplicationQuery
+ include CustomSortable
+
+ attr_reader :params
+
+ sort_columns :updated_at, default_by: :updated_at, default_direction: :desc
+
+ def initialize(params)
+ @params = params
+ end
+
+ def call
+ status =
+ case params[:status]
+ when 'processed' then %w(agreed refused)
+ else params[:status]
+ end
+ applies = LibraryApply.where(status: status) if status.present?
+
+ # 关键字模糊查询
+ keyword = params[:keyword].to_s.strip
+ if keyword.present?
+ applies = applies.joins(:library)
+ .where('title LIKE :keyword OR uuid 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/myshixun_query.rb b/app/queries/admins/myshixun_query.rb
new file mode 100644
index 000000000..bfbb98d64
--- /dev/null
+++ b/app/queries/admins/myshixun_query.rb
@@ -0,0 +1,26 @@
+class Admins::MyshixunQuery < 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
+ objs = Myshixun.all
+
+ keyword = params[:keyword].to_s.strip
+ if keyword.present?
+ like_sql = 'users.login LIKE :keyword OR CONCAT(users.lastname, users.firstname) LIKE :keyword OR '\
+ 'schools.name LIKE :keyword OR shixuns.name LIKE :keyword OR CONCAT(teacher.lastname, teacher.firstname) Like :keyword'
+ objs = objs.joins(:shixun, user: { user_extension: :school })
+ .joins('JOIN users teacher ON teacher.id = shixuns.user_id')
+ .where(like_sql, keyword: "%#{keyword}%")
+ end
+
+ custom_sort(objs, params[:sort_by], params[:sort_direction])
+ end
+end
\ No newline at end of file
diff --git a/app/queries/admins/shixun_query.rb b/app/queries/admins/shixun_query.rb
new file mode 100644
index 000000000..0d726f267
--- /dev/null
+++ b/app/queries/admins/shixun_query.rb
@@ -0,0 +1,48 @@
+class Admins::ShixunQuery < 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
+ all_shixuns = Shixun.all
+ status =
+ case params[:status]
+ when "editing" then [0]
+ when "pending" then [1]
+ when "processed" then [2]
+ when "closed" then [3]
+ else
+ [0,1,2,3]
+ end
+
+ all_shixuns = all_shixuns.where(status: status) if status.present?
+
+ if params[:tag].present?
+ all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)
+ end
+
+ # 关键字模糊查询
+ keyword = params[:keyword].to_s.strip
+ if keyword.present?
+ search_type = params[:search_type] || "0"
+ case search_type
+ when "0"
+ all_shixuns = all_shixuns.joins(:user)
+ .where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%")
+ when "1"
+ all_shixuns = all_shixuns.where('name like :keyword', keyword: "%#{keyword}%")
+ else
+ all_shixuns = all_shixuns.joins(user: {user_extension: :school}).where('schools.name LIKE ?', "%#{keyword}%")
+ end
+
+ end
+
+ custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
+ end
+end
\ No newline at end of file
diff --git a/app/queries/admins/shixun_settings_query.rb b/app/queries/admins/shixun_settings_query.rb
new file mode 100644
index 000000000..32cfdb8bf
--- /dev/null
+++ b/app/queries/admins/shixun_settings_query.rb
@@ -0,0 +1,54 @@
+class Admins::ShixunSettingsQuery < 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
+ all_shixuns = Shixun.all
+ status =
+ case params[:status]
+ when "editing" then [0]
+ when "pending" then [1]
+ when "processed" then [2]
+ when "closed" then [3]
+ else
+ [0,1,2,3]
+ end
+
+ all_shixuns = all_shixuns.where(status: status) if status.present?
+
+ if params[:tag].present?
+ all_shixuns = all_shixuns.joins(:mirror_repositories).where("mirror_repositories.id = ?",params[:tag].to_i)
+ end
+
+ # 关键字模糊查询
+ keyword = params[:keyword].to_s.strip
+ if keyword.present?
+ search_type = params[:search_type] || "0"
+ case search_type
+ when "0"
+ all_shixuns = all_shixuns.joins(:user)
+ .where('CONCAT(lastname, firstname) like :keyword', keyword: "%#{keyword}%")
+ when "1"
+ all_shixuns = all_shixuns.where('name like :keyword', keyword: "%#{keyword}%")
+ else
+ all_shixuns = all_shixuns.joins(user: {user_extension: :school}).where('schools.name LIKE ?', "%#{keyword}%")
+ end
+ end
+
+ all_shixuns = all_shixuns.where(can_copy: params[:can_copy]) if params[:can_copy]
+ all_shixuns = all_shixuns.where(webssh: params[:webssh]) if params[:webssh]
+ all_shixuns = all_shixuns.where(hidden: params[:hidden]) if params[:hidden]
+ all_shixuns = all_shixuns.where(homepage_show: params[:homepage_show]) if params[:homepage_show]
+ all_shixuns = all_shixuns.where(task_pass: params[:task_pass]) if params[:task_pass]
+ all_shixuns = all_shixuns.where(code_hidden: params[:code_hidden]) if params[:code_hidden]
+
+ custom_sort(all_shixuns, params[:sort_by], params[:sort_direction])
+ end
+end
\ No newline at end of file
diff --git a/app/queries/admins/user_query.rb b/app/queries/admins/user_query.rb
index 5a633f059..75e50fc1b 100644
--- a/app/queries/admins/user_query.rb
+++ b/app/queries/admins/user_query.rb
@@ -28,7 +28,13 @@ class Admins::UserQuery < ApplicationQuery
keyword = params[:keyword].to_s.strip.presence
if keyword
sql = 'CONCAT(lastname, firstname) LIKE :keyword OR login LIKE :keyword OR mail LIKE :keyword OR phone LIKE :keyword'
- users = users.where(sql, keyword: keyword)
+ users = users.where(sql, keyword: "%#{keyword}%")
+ end
+
+ # 姓名
+ name = params[:name].to_s.strip.presence
+ if name.present?
+ users = users.where('CONCAT(lastname, firstname) LIKE :name', name: "%#{name}%")
end
# 学校名称
diff --git a/app/services/admins/add_department_member_service.rb b/app/services/admins/add_department_member_service.rb
new file mode 100644
index 000000000..f8331cf4a
--- /dev/null
+++ b/app/services/admins/add_department_member_service.rb
@@ -0,0 +1,20 @@
+class Admins::AddDepartmentMemberService < ApplicationService
+
+ attr_reader :department, :params
+
+ def initialize(department, params)
+ @department = department
+ @params = params
+ end
+
+ def call
+ columns = %i[]
+ DepartmentMember.bulk_insert(*columns) do |worker|
+ Array.wrap(params[:user_ids]).compact.each do |user_id|
+ next if department.department_members.exists?(user_id: user_id)
+
+ worker.add(department_id: department.id, user_id: user_id)
+ end
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/admins/check_shixun_mirrors_service.rb b/app/services/admins/check_shixun_mirrors_service.rb
new file mode 100644
index 000000000..868fab042
--- /dev/null
+++ b/app/services/admins/check_shixun_mirrors_service.rb
@@ -0,0 +1,89 @@
+class Admins::CheckShixunMirrorsService < ApplicationService
+ Error = Class.new(StandardError)
+
+ def call
+ bridge_images
+
+ ActiveRecord::Base.transaction do
+ check_sync_mirrors!
+
+ check_mirrors!
+ end
+ end
+
+ private
+
+ def mirrors
+ bridge_images['images']
+ end
+
+ def sync_mirrors
+ bridge_images['imagesNotSync']
+ end
+
+ def check_mirrors!
+ return if mirrors.blank?
+ image_names = []
+
+ mirrors.each do |data|
+ mirror = JSON.parse(data)
+
+ name_repository = MirrorRepository.find_by(name: mirror['imageName'])
+ id_repository = MirrorRepository.find_by(mirrorID: mirror['imageID'])
+
+ image_names << mirror['imageName']
+
+ if name_repository.blank? && id_repository.present? # 镜像名称被修改
+ id_repository.update_column(:status, 2)
+ MirrorOperationRecord.create!(mirror_repository_id: id_repository.id, mirror_id: mirror['imageID'],
+ mirror_name: mirror['imageName'], status: 2, user_id: -1)
+ elsif name_repository.blank? # 镜像不存在、创建镜像
+ new_repository = MirrorRepository.create!(mirrorID: mirror['imageID'], name: mirror['imageName'])
+ MirrorOperationRecord.create!(mirror_repository_id: new_repository.id, mirror_id: mirror['imageID'],
+ mirror_name: mirror['imageName'], status: 0, user_id: -1)
+ elsif name_repository.mirrorID != mirror['imageID'] # 镜像ID被修改
+ name_repository.update_column(:status, 2)
+ MirrorOperationRecord.create!(mirror_repository_id: name_repository.id, mirror_id: mirror['imageID'],
+ mirror_name: mirror['imageName'], status: 1, user_id: -1)
+ end
+ end
+
+ # 判断中间层镜像是否被删除
+ MirrorRepository.find_each do |mirror|
+ next if mirror&.name.blank? || image_names.index(mirror.name)
+
+ mirror.update_column(:status, 4)
+ MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: mirror&.mirrorID,
+ mirror_name: mirror.name, status: 3, user_id: -1)
+ end
+ end
+
+ def check_sync_mirrors!
+ return if sync_mirrors.blank?
+
+ sync_mirrors.each do |data|
+ mirror = JSON.parse(data)
+
+ repository = MirrorRepository.find_by(name: mirror['imageName'])
+ next if repository.blank? || repository.status != 1
+
+ repository.update_column(:status, 5)
+ MirrorOperationRecord.create!(mirror_repository_id: repository.id, mirror_id: mirror['imageID'],
+ mirror_name: mirror['imageName'], status: 4, user_id: -1)
+ end
+ end
+
+ def bridge_images
+ @_bridge_images ||= begin
+ url = EduSetting.get('cloud_bridge')
+ res = Faraday.get(url)
+
+ raise Error, '拉取镜像信息异常' if res && res['code'].nonzero?
+
+ res
+ rescue => e
+ Rails.logger.error("get response failed ! #{e.message}")
+ raise Error, '实训云平台繁忙(繁忙等级:84)'
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/admins/choose_mirror_service.rb b/app/services/admins/choose_mirror_service.rb
new file mode 100644
index 000000000..77d187884
--- /dev/null
+++ b/app/services/admins/choose_mirror_service.rb
@@ -0,0 +1,21 @@
+class Admins::ChooseMirrorService < ApplicationService
+ attr_reader :mirror, :user, :number
+
+ def initialize(mirror, user, mirror_number)
+ @mirror = mirror
+ @user = user
+ @number = mirror_number
+ end
+
+ def call
+ if mirror.mirrorID == number
+ mirror.update_column(:status, 1)
+ return
+ end
+
+ old_number = mirror.mirrorID
+ mirror.update!(mirrorID: number, status: 1)
+ MirrorOperationRecord.create!(mirror_repository_id: mirror.id, mirror_id: number, mirror_name: mirror.name,
+ status: 1, user_id: user.id, old_tag: old_number, new_tag: mirror.mirrorID)
+ end
+end
\ No newline at end of file
diff --git a/app/services/admins/save_mirror_repository_service.rb b/app/services/admins/save_mirror_repository_service.rb
new file mode 100644
index 000000000..4aff64f66
--- /dev/null
+++ b/app/services/admins/save_mirror_repository_service.rb
@@ -0,0 +1,37 @@
+class Admins::SaveMirrorRepositoryService < ApplicationService
+ Error = Class.new(StandardError)
+
+ attr_reader :mirror, :user, :params
+
+ def initialize(mirror, user, params)
+ @mirror = mirror
+ @user = user
+ @params = params
+ end
+
+ def call
+ mirror.assign_attributes(params)
+
+ raise Error, '镜像别名重复' if MirrorRepository.where.not(id: mirror.id).exists?(type_name: params[:type_name])
+
+ ActiveRecord::Base.transaction do
+ record_operation! if mirror.persisted?
+
+ mirror.save!
+ end
+ end
+
+ private
+
+ def record_operation!
+ if mirror.type_name_changed?
+ MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5,
+ user_id: user.id, old_tag: mirror.type_name_in_database,
+ new_tag: mirror.type_name)
+ elsif mirror.status_changed?
+ MirrorOperationRecord.create!(mirror_repository_id: mirror.id, status: 5,
+ user_id: user.id, old_tag: mirror.status_in_database,
+ new_tag: mirror.status)
+ end
+ end
+end
\ No newline at end of file
diff --git a/app/services/homeworks_service.rb b/app/services/homeworks_service.rb
index 64aec92c6..f6868afba 100644
--- a/app/services/homeworks_service.rb
+++ b/app/services/homeworks_service.rb
@@ -298,6 +298,9 @@ class HomeworksService
else
0
end
+ else
+ adjust_score = work.challenge_work_scores.select{|work_score| work_score.challenge_id == game.challenge_id}.last
+ final_score += adjust_score.score if adjust_score.present?
end
end
@@ -314,8 +317,8 @@ class HomeworksService
if work.work_status != 0
if myshixun_endtime.present?
- work.cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i
-
+ work_cost_time = myshixun_endtime.to_i - setting_time.publish_time.to_i
+ work.cost_time = work_cost_time > 0 ? work_cost_time : games.select{|game| game.status == 2}.pluck(:cost_time).sum
efficiency = (pass_consume_time == 0 ? 0 : Math.log((user_total_score / pass_consume_time.to_f) + 1.0))
work.efficiency = format("%.2f", efficiency)
diff --git a/app/services/users/question_bank_service.rb b/app/services/users/question_bank_service.rb
index b17073a4f..7e640c6a5 100644
--- a/app/services/users/question_bank_service.rb
+++ b/app/services/users/question_bank_service.rb
@@ -22,8 +22,8 @@ class Users::QuestionBankService
course_lists = CourseList.joins(relation_name).where.not(relation_name => { id: nil })
category_condition =
- case params[:category]
- when 'common' then { homework_type: 1 }
+ case params[:object_type]
+ when 'normal' then { homework_type: 1 }
when 'group' then { homework_type: 3 }
when 'exercise' then { container_type: 'Exercise' }
when 'poll' then { container_type: 'Poll' }
@@ -47,8 +47,8 @@ class Users::QuestionBankService
def class_name
@_class_name ||= begin
- case params[:category]
- when 'common', 'group' then 'HomeworkBank'
+ case params[:object_type]
+ when 'normal', 'group' then 'HomeworkBank'
when 'exercise', 'poll' then 'ExerciseBank'
when 'gtask' then 'GtaskBank'
when 'gtopic' then 'GtopicBank'
@@ -58,8 +58,8 @@ class Users::QuestionBankService
end
def category_filter(relations)
- case params[:category]
- when 'common' then
+ case params[:object_type]
+ when 'normal' then
relations.where(homework_type: 1)
when 'group' then
relations.where(homework_type: 3)
diff --git a/app/templates/shared/main.css b/app/templates/shared/main.css
index 9e9bc4f50..884f6fa37 100644
--- a/app/templates/shared/main.css
+++ b/app/templates/shared/main.css
@@ -344,7 +344,7 @@ a.edu-txt-w40,.edu-txt-w40{ width:40px; display: inline-block;text-align: center
.bor-grey01{border:1px solid #E6EAEB;}
.bor-orange{border:1px solid #FF7500;}
.bor-blue{border:1px solid #5faee3;}
-.bor-red{border:1px solid #db0505;}
+.bor-red{border:1px solid #db0505 !important;}
.bor-none{border:none;}
.bor-outnone{outline:none; border:0px;}
diff --git a/app/templates/shixun_work/shixun_work.html.erb b/app/templates/shixun_work/shixun_work.html.erb
index f4aec2ea6..a6ef48c3e 100644
--- a/app/templates/shixun_work/shixun_work.html.erb
+++ b/app/templates/shixun_work/shixun_work.html.erb
@@ -66,15 +66,19 @@
关卡
- 任务名称
- 开启时间
+ 任务名称
+ 开启时间
评测次数
完成时间
耗时
经验值
+ 关卡得分
+ 调分
<% @games.each_with_index do |game, index| %>
+ <% challenge_score = @homework.challenge_score game.challenge_id %>
+ <% game_score = @work.work_challenge_score game, challenge_score %>
<%= index + 1 %>
@@ -88,6 +92,8 @@
<%= finished_time game.end_time %>
<%= ApplicationController.helpers.time_consuming game %>
<%= game.final_score %> / <%= game.challenge.all_score %>
+ <%= game_score %> / <%= challenge_score %>
+ <%= game_score %>
<% end %>
diff --git a/app/views/admins/choose_mirror_repositories/create.js.erb b/app/views/admins/choose_mirror_repositories/create.js.erb
new file mode 100644
index 000000000..585ecb1af
--- /dev/null
+++ b/app/views/admins/choose_mirror_repositories/create.js.erb
@@ -0,0 +1,5 @@
+$.notify({ message: '操作成功' },{ type: 'success' });
+
+setTimeout(function(){
+ window.location.reload();
+}, 500)
\ No newline at end of file
diff --git a/app/views/admins/choose_mirror_repositories/new.js.erb b/app/views/admins/choose_mirror_repositories/new.js.erb
new file mode 100644
index 000000000..8603011ab
--- /dev/null
+++ b/app/views/admins/choose_mirror_repositories/new.js.erb
@@ -0,0 +1,2 @@
+$('.admin-modal-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/choose_mirror_modal', locals: { mirror: @mirror, new_mirror: @new_mirror } ) %>");
+$('.modal.admin-choose-mirror-modal').modal('show');
\ No newline at end of file
diff --git a/app/views/admins/daily_school_statistics/index.html.erb b/app/views/admins/daily_school_statistics/index.html.erb
index 054e06fc6..39dcba633 100644
--- a/app/views/admins/daily_school_statistics/index.html.erb
+++ b/app/views/admins/daily_school_statistics/index.html.erb
@@ -5,7 +5,7 @@
@@ -33,19 +33,19 @@
-
New users
- 2,356
+ 7天内活跃用户数
+ <%= @weekly_active_user_count %>
-
- 3.48%
- Since last week
-
+
+
+
+
@@ -54,19 +54,19 @@
-
Sales
- 924
+ 30天内活跃用户数
+ <%= @month_active_user_count %>
-
- 1.10%
- Since yesterday
-
+
+
+
+
@@ -75,19 +75,19 @@
-
Performance
- 49,65%
+ 30天内新增用户数
+ <%= @new_user_count %>
-
- 12%
- Since last month
-
+
+
+
+
@@ -95,94 +95,124 @@
-
+
+
-
-
-
-
-
-
- Test
- Test
- Test
- Test
-
-
-
- <% 5.times do %>
-
- /test/
- 4,569
- 340
-
- 46,53%
-
-
- <% end %>
-
-
-
+
+
+
+
+
+
+
+
+
-
-
-
-
- Test
- Test
-
-
-
-
- <% 5.times do %>
-
-
- Test
-
-
- 1,480
-
-
-
-
-
- <% end %>
-
-
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%# 5.times do %>
+
+
+
+
+
+
+
+
+ <%# end %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%# 5.times do %>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <%# end %>
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/department_members/create.js.erb b/app/views/admins/department_members/create.js.erb
new file mode 100644
index 000000000..4355c7432
--- /dev/null
+++ b/app/views/admins/department_members/create.js.erb
@@ -0,0 +1,4 @@
+$('.modal.admin-add-department-member-modal').modal('hide');
+$.notify({ message: '操作成功' });
+
+$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")
\ No newline at end of file
diff --git a/app/views/admins/department_members/destroy.js.erb b/app/views/admins/department_members/destroy.js.erb
new file mode 100644
index 000000000..d3eb3755b
--- /dev/null
+++ b/app/views/admins/department_members/destroy.js.erb
@@ -0,0 +1,2 @@
+$.notify({ message: '操作成功' });
+$('.department-list-container .department-item-<%= current_department.id %> .member-user-item-<%= @member.user_id %>').remove();
\ No newline at end of file
diff --git a/app/views/admins/departments/edit.js.erb b/app/views/admins/departments/edit.js.erb
new file mode 100644
index 000000000..dc86d3ae0
--- /dev/null
+++ b/app/views/admins/departments/edit.js.erb
@@ -0,0 +1,2 @@
+$('.admin-modal-container').html("<%= j( render partial: 'admins/departments/shared/edit_department_modal', locals: { department: current_department } ) %>");
+$('.modal.admin-edit-department-modal').modal('show');
\ No newline at end of file
diff --git a/app/views/admins/departments/index.html.erb b/app/views/admins/departments/index.html.erb
new file mode 100644
index 000000000..9d0d49358
--- /dev/null
+++ b/app/views/admins/departments/index.html.erb
@@ -0,0 +1,33 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('部门列表') %>
+<% end %>
+
+
+
+
+ <%= render partial: 'admins/departments/shared/list',
+ locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count } %>
+
+
+<%= render 'admins/departments/shared/create_department_modal' %>
+<%= render 'admins/departments/shared/add_department_member_modal' %>
+<%= render 'admins/departments/shared/merge_department_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/departments/index.js.erb b/app/views/admins/departments/index.js.erb
new file mode 100644
index 000000000..bd2e4b25d
--- /dev/null
+++ b/app/views/admins/departments/index.js.erb
@@ -0,0 +1 @@
+$('.department-list-container').html("<%= j(render partial: 'admins/departments/shared/list', locals: { departments: @departments, users_count: @users_count, professional_auth_count: @professional_auth_count }) %>");
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_add_department_member_modal.html.erb b/app/views/admins/departments/shared/_add_department_member_modal.html.erb
new file mode 100644
index 000000000..5d2707222
--- /dev/null
+++ b/app/views/admins/departments/shared/_add_department_member_modal.html.erb
@@ -0,0 +1,30 @@
+
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_create_department_modal.html.erb b/app/views/admins/departments/shared/_create_department_modal.html.erb
new file mode 100644
index 000000000..ae6605eb8
--- /dev/null
+++ b/app/views/admins/departments/shared/_create_department_modal.html.erb
@@ -0,0 +1,35 @@
+
\ 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
new file mode 100644
index 000000000..11584909d
--- /dev/null
+++ b/app/views/admins/departments/shared/_department_item.html.erb
@@ -0,0 +1,34 @@
+<% not_list = defined?(:users_count) %>
+
+<%= overflow_hidden_span department.name, width: 150 %>
+<%= overflow_hidden_span department.school.name, width: 150 %>
+
+<% if not_list %>
+ <%= department.user_extensions.count %>
+ <%= department.user_extensions.joins(:user).where(users: { professional_certification: true }).count %>
+<% else %>
+ <%= users_count.fetch(department.id, 0) %>
+ <%= professional_auth_count.fetch(department.id, 0) %>
+<% end %>
+
+
+ <%= render partial: 'admins/departments/shared/member_users', locals: { department: department } %>
+
+
+ <% if department.identifier.present? %>
+ <%= link_to department.identifier.to_s, statistics_college_path(department.identifier), target: '_blank' %>
+ <% else %>
+ --
+ <% end %>
+
+<%= department.host_count %>
+<%= department.created_at&.strftime('%Y-%m-%d %H:%M') %>
+
+ <%= link_to '编辑', edit_admins_department_path(department), remote: true, class: 'action' %>
+
+ <%= 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' } %>
+
+ <%= 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/_edit_department_modal.html.erb b/app/views/admins/departments/shared/_edit_department_modal.html.erb
new file mode 100644
index 000000000..38b43bbce
--- /dev/null
+++ b/app/views/admins/departments/shared/_edit_department_modal.html.erb
@@ -0,0 +1,25 @@
+
+
+
+
+
+ <%= simple_form_for([:admins, department], html: { class: 'admin-edit-department-form' }, defaults: { wrapper_html: { class: 'offset-md-1 col-md-10' } }) do |f| %>
+ <%= f.input :name, as: :string, label: '名称' %>
+ <%= f.input :identifier, as: :string, label: '统计链接' %>
+ <%= f.input :host_count, as: :integer, label: '云主机数' %>
+
+
+ <% end %>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_list.html.erb b/app/views/admins/departments/shared/_list.html.erb
new file mode 100644
index 000000000..6af63d6f4
--- /dev/null
+++ b/app/views/admins/departments/shared/_list.html.erb
@@ -0,0 +1,28 @@
+
+
+
+ 部门名称
+ 单位名称
+ 用户数
+ 已职业认证
+ 部门管理员
+ 统计链接
+ 云主机数
+ <%= sort_tag('创建时间', name: 'created_at', path: admins_departments_path) %>
+ 操作
+
+
+
+ <% if departments.present? %>
+ <% departments.each do |department| %>
+
+ <%= render 'admins/departments/shared/department_item', department: department %>
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: departments } %>
\ No newline at end of file
diff --git a/app/views/admins/departments/shared/_member_users.html.erb b/app/views/admins/departments/shared/_member_users.html.erb
new file mode 100644
index 000000000..8d4d466db
--- /dev/null
+++ b/app/views/admins/departments/shared/_member_users.html.erb
@@ -0,0 +1,12 @@
+
+ <% department.member_users.each do |user| %>
+
+ <%= link_to user.real_name, "/users/#{user.login}", target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } %>
+ <%= link_to(admins_department_department_member_path(department, user_id: user.id),
+ method: :delete, remote: true, class: 'ml-1 delete-member-action',
+ data: { confirm: '确认删除吗?' }) do %>
+
+ <% end %>
+
+ <% end %>
+
\ 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
new file mode 100644
index 000000000..200e75ccd
--- /dev/null
+++ b/app/views/admins/departments/shared/_merge_department_modal.html.erb
@@ -0,0 +1,31 @@
+
\ No newline at end of file
diff --git a/app/views/admins/departments/update.js.erb b/app/views/admins/departments/update.js.erb
new file mode 100644
index 000000000..359bac59c
--- /dev/null
+++ b/app/views/admins/departments/update.js.erb
@@ -0,0 +1,4 @@
+$('.modal.admin-edit-department-modal').modal('hide');
+$.notify({ message: '操作成功' });
+
+$('.department-list-table .department-item-<%= current_department.id %>').html("<%= j(render partial: 'admins/departments/shared/department_item', locals: { department: current_department }) %>")
\ 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 170a8fc4a..38b7dfd63 100644
--- a/app/views/admins/identity_authentications/index.html.erb
+++ b/app/views/admins/identity_authentications/index.html.erb
@@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
diff --git a/app/views/admins/library_applies/index.html.erb b/app/views/admins/library_applies/index.html.erb
new file mode 100644
index 000000000..55a7e9e09
--- /dev/null
+++ b/app/views/admins/library_applies/index.html.erb
@@ -0,0 +1,32 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('教学案例发布') %>
+<% end %>
+
+
+
+
+ <%= render(partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies }) %>
+
+
+<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>
\ No newline at end of file
diff --git a/app/views/admins/library_applies/index.js.erb b/app/views/admins/library_applies/index.js.erb
new file mode 100644
index 000000000..6f4c3e712
--- /dev/null
+++ b/app/views/admins/library_applies/index.js.erb
@@ -0,0 +1 @@
+$('.library-applies-list-container').html("<%= j( render partial: 'admins/library_applies/shared/list', locals: { applies: @library_applies } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/library_applies/shared/_list.html.erb b/app/views/admins/library_applies/shared/_list.html.erb
new file mode 100644
index 000000000..c6f9825dc
--- /dev/null
+++ b/app/views/admins/library_applies/shared/_list.html.erb
@@ -0,0 +1,56 @@
+<% is_processed = params[:status].to_s != 'pending' %>
+
+
+
+
+ 头像
+ 姓名
+ 教学案例
+ 案例描述
+ 时间
+ <% if is_processed %>
+ 拒绝原因
+ 状态
+ <% else %>
+ 操作
+ <% end %>
+
+
+
+ <% if applies.present? %>
+ <% applies.each do |apply| %>
+ <% user = apply.library.user %>
+ <% library = apply.library %>
+
+
+ <%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
+
+ <% end %>
+
+ <%= user.real_name %>
+ <%= 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') %>
+
+ <% if is_processed %>
+ <%= overflow_hidden_span apply.reason %>
+ <%= t("library_apply.status.#{apply.status}") %>
+ <% else %>
+
+ <%= agree_link '同意', agree_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
+ <%= javascript_void_link('拒绝', class: 'action refuse-action',
+ data: {
+ toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
+ url: refuse_admins_library_apply_path(apply, element: ".library_applies-#{apply.id}")
+ }) %>
+
+ <% end %>
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/edit.html.erb b/app/views/admins/mirror_repositories/edit.html.erb
new file mode 100644
index 000000000..7df580c96
--- /dev/null
+++ b/app/views/admins/mirror_repositories/edit.html.erb
@@ -0,0 +1,8 @@
+<%
+ define_admin_breadcrumbs do
+ add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path)
+ add_admin_breadcrumb('镜像详情')
+ end
+%>
+
+<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'update' } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/index.html.erb b/app/views/admins/mirror_repositories/index.html.erb
new file mode 100644
index 000000000..ac384408f
--- /dev/null
+++ b/app/views/admins/mirror_repositories/index.html.erb
@@ -0,0 +1,23 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('镜像管理') %>
+<% end %>
+
+
+
+ <%= link_to '新建', new_admins_mirror_repository_path, class: 'btn btn-primary' %>
+
+
+<% if @error_mirror_names.present? %>
+
+ 以下镜像异常:
+ <% @error_mirror_names.each do |mirror_name| %>
+ <%= mirror_name %>
+ <% end %>
+
+<% end %>
+
+
+ <%= render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } %>
+
+
+<%= render 'admins/mirror_repositories/shared/replace_mirror_modal' %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/index.js.erb b/app/views/admins/mirror_repositories/index.js.erb
new file mode 100644
index 000000000..58ccb1ef8
--- /dev/null
+++ b/app/views/admins/mirror_repositories/index.js.erb
@@ -0,0 +1 @@
+$('.mirror-repository-list-container').html("<%= j( render partial: 'admins/mirror_repositories/shared/list', locals: { mirrors: @mirrors } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/merge.js.erb b/app/views/admins/mirror_repositories/merge.js.erb
new file mode 100644
index 000000000..585ecb1af
--- /dev/null
+++ b/app/views/admins/mirror_repositories/merge.js.erb
@@ -0,0 +1,5 @@
+$.notify({ message: '操作成功' },{ type: 'success' });
+
+setTimeout(function(){
+ window.location.reload();
+}, 500)
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/new.html.erb b/app/views/admins/mirror_repositories/new.html.erb
new file mode 100644
index 000000000..792fe0857
--- /dev/null
+++ b/app/views/admins/mirror_repositories/new.html.erb
@@ -0,0 +1,8 @@
+<%
+ define_admin_breadcrumbs do
+ add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path)
+ add_admin_breadcrumb('新建镜像')
+ end
+%>
+
+<%= render partial: 'admins/mirror_repositories/shared/form', locals: { mirror: @mirror, form_action: 'create' } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb b/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb
new file mode 100644
index 000000000..99c846c70
--- /dev/null
+++ b/app/views/admins/mirror_repositories/shared/_choose_mirror_modal.html.erb
@@ -0,0 +1,42 @@
+
+
+
+
+
+ <%= form_tag(admins_choose_mirror_repositories_path(mirror_id: mirror.id), method: :post, class: 'admin-choose-mirror-form') do %>
+
+
+
+
+ <% end %>
+
+
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/shared/_form.html.erb b/app/views/admins/mirror_repositories/shared/_form.html.erb
new file mode 100644
index 000000000..c8ab2a186
--- /dev/null
+++ b/app/views/admins/mirror_repositories/shared/_form.html.erb
@@ -0,0 +1,42 @@
+
+ <%= simple_form_for([:admins, mirror], url: { action: form_action }, html: { class: 'edit-mirror col-md-12' }, defaults: { wrapper_html: { class: 'col-md-4' } }) do |f| %>
+ <% unless mirror.new_record? %>
+
+ <%= f.input :mirrorID, label: '镜像ID', input_html: { readonly: true, class: 'form-control-plaintext' } %>
+ <%= f.input :name, label: '镜像名称', input_html: { readonly: true, class: 'form-control-plaintext' } %>
+
+ <% end %>
+
+
+ <%= f.input :type_name, as: :string, label: '镜像别名 *' %>
+
+
+ <%= f.label :main_type, label: '类别' %>
+ <%= f.select :main_type, [['主类别', 1],['小类别', 0]], {}, class: 'form-control optional' %>
+
+
+
+
+ <%= f.input :time_limit, as: :integer, label: '评测时限(S)' %>
+ <%= f.input :resource_limit, as: :integer, label: '磁盘限制(K)' %>
+
+
+
+ <%= f.input :cpu_limit, as: :integer, label: 'CPU限制(核)' %>
+ <%= f.input :memory_limit, as: :integer, label: '内存限制(M)' %>
+
+
+
+ <%= f.input :description, as: :text, label: '描述', wrapper_html: { class: 'col-md-8' } %>
+
+
+
+ <%= f.input :status, as: :radio_buttons, label: '状态', collection: [%w(未发布 0), %w(已发布 1)], wrapper_html: { class: 'col-md-4' } %>
+
+
+
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %>
+ <%= link_to '取消', admins_mirror_repositories_path, class: 'btn btn-secondary px-4' %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/shared/_list.html.erb b/app/views/admins/mirror_repositories/shared/_list.html.erb
new file mode 100644
index 000000000..fcf0d03a2
--- /dev/null
+++ b/app/views/admins/mirror_repositories/shared/_list.html.erb
@@ -0,0 +1,54 @@
+
+
+
+ ID
+ 类别
+ 镜像别名
+ 镜像名称
+ 镜像描述
+ 修改时间
+ 脚本
+ 状态
+ 操作
+
+
+
+ <% if mirrors.present? %>
+ <% mirrors.each do |mirror| %>
+
+ <%= mirror.id %>
+ <%= mirror_type_tag(mirror) %>
+ <%= display_text(mirror.type_name) %>
+ <%= overflow_hidden_span mirror.name, width: 150 %>
+ <%= overflow_hidden_span mirror.description, width: 240 %>
+ <%= mirror.updated_at.strftime('%Y-%m-%d %H:%M') %>
+
+ <% if mirror.main_type == "1" %>
+ <%= link_to admins_mirror_repository_mirror_scripts_path(mirror) do %>
+
+ <% end %>
+ <% end %>
+
+ <%= mirror_status_tag mirror %>
+
+ <%= link_to '编辑', edit_admins_mirror_repository_path(mirror), class: 'action edit-action' %>
+
+ <% if mirror.status == 2 %>
+ <%= link_to '同步', new_admins_choose_mirror_repository_path(mirror_id: mirror.id), remote: true, class: 'action sync-action' %>
+ <% end %>
+
+ <%= javascript_void_link '替换', class: 'action replace-action', data: { toggle: 'modal', target: '.admin-replace-mirror-modal', id: mirror.id, name: mirror.name } %>
+
+ <% if mirror.deletable? %>
+ <%= delete_link '删除', admins_mirror_repository_path(mirror, element: ".mirror-repository-item-#{mirror.id}"), class: 'delete-mirror-repository-action' %>
+ <% end %>
+
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: mirrors } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb b/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb
new file mode 100644
index 000000000..f2b2d20c8
--- /dev/null
+++ b/app/views/admins/mirror_repositories/shared/_replace_mirror_modal.html.erb
@@ -0,0 +1,33 @@
+
\ No newline at end of file
diff --git a/app/views/admins/mirror_scripts/edit.html.erb b/app/views/admins/mirror_scripts/edit.html.erb
new file mode 100644
index 000000000..bc3a6ec91
--- /dev/null
+++ b/app/views/admins/mirror_scripts/edit.html.erb
@@ -0,0 +1,8 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path) %>
+ <% add_admin_breadcrumb(current_mirror.type_name, edit_admins_mirror_repository_path(current_mirror)) %>
+ <% add_admin_breadcrumb('脚本列表', admins_mirror_repository_mirror_scripts_path(current_mirror)) %>
+ <% add_admin_breadcrumb('编辑脚本') %>
+<% end %>
+
+<%= render partial: 'admins/mirror_scripts/shared/form', locals: { mirror: current_mirror, script: @script, form_action: 'update' } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_scripts/index.html.erb b/app/views/admins/mirror_scripts/index.html.erb
new file mode 100644
index 000000000..f4fa398af
--- /dev/null
+++ b/app/views/admins/mirror_scripts/index.html.erb
@@ -0,0 +1,14 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path) %>
+ <% add_admin_breadcrumb(current_mirror.type_name, edit_admins_mirror_repository_path(current_mirror)) %>
+ <% add_admin_breadcrumb('脚本列表') %>
+<% end %>
+
+
+
+ <%= link_to '新建', new_admins_mirror_repository_mirror_script_path(current_mirror), class: 'btn btn-primary' %>
+
+
+
+ <%= render partial: 'admins/mirror_scripts/shared/list', locals: { mirror: current_mirror, scripts: @scripts } %>
+
diff --git a/app/views/admins/mirror_scripts/new.html.erb b/app/views/admins/mirror_scripts/new.html.erb
new file mode 100644
index 000000000..4d6717f41
--- /dev/null
+++ b/app/views/admins/mirror_scripts/new.html.erb
@@ -0,0 +1,8 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('镜像管理', admins_mirror_repositories_path) %>
+ <% add_admin_breadcrumb(current_mirror.type_name, edit_admins_mirror_repository_path(current_mirror)) %>
+ <% add_admin_breadcrumb('脚本列表', admins_mirror_repository_mirror_scripts_path(current_mirror)) %>
+ <% add_admin_breadcrumb('新建脚本') %>
+<% end %>
+
+<%= render partial: 'admins/mirror_scripts/shared/form', locals: { mirror: current_mirror, script: @script, form_action: 'create' } %>
\ No newline at end of file
diff --git a/app/views/admins/mirror_scripts/shared/_form.html.erb b/app/views/admins/mirror_scripts/shared/_form.html.erb
new file mode 100644
index 000000000..c538e9f73
--- /dev/null
+++ b/app/views/admins/mirror_scripts/shared/_form.html.erb
@@ -0,0 +1,12 @@
+
+ <%= simple_form_for([:admins, mirror, script], url: { action: form_action }, html: { class: 'script-form' }) do |f| %>
+ <%= f.input :script_type, label: '名称', input_html: { class: 'col-md-6' } %>
+ <%= f.input :description, as: :text, label: '说明', input_html: { class: 'col-md-6' } %>
+ <%= f.input :script, as: :text, label: '评测脚本' %>
+
+
+ <%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4', 'data-disable-with': '保存中...' %>
+ <%= link_to '取消', admins_mirror_repository_mirror_scripts_path(mirror), class: 'btn btn-secondary px-4' %>
+
+ <% end %>
+
\ No newline at end of file
diff --git a/app/views/admins/mirror_scripts/shared/_list.html.erb b/app/views/admins/mirror_scripts/shared/_list.html.erb
new file mode 100644
index 000000000..30aff38c7
--- /dev/null
+++ b/app/views/admins/mirror_scripts/shared/_list.html.erb
@@ -0,0 +1,32 @@
+
+
+
+ ID
+ 名称
+ 说明
+ 更新时间
+ 操作
+
+
+
+ <% if scripts.present? %>
+ <% scripts.each do |script| %>
+
+ <%= script.id %>
+ <%= overflow_hidden_span script.script_type, width: 200 %>
+ <%= overflow_hidden_span script.description, width: 400 %>
+ <%= script.updated_at.strftime('%Y-%m-%d %H:%M') %>
+
+ <%= link_to '编辑', edit_admins_mirror_repository_mirror_script_path(mirror, script), class: 'action edit-action' %>
+
+ <%= delete_link '删除', admins_mirror_repository_mirror_script_path(mirror, script, element: ".mirror-script-item-#{script.id}"), class: 'delete-mirror-script-action' %>
+
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: scripts } %>
\ No newline at end of file
diff --git a/app/views/admins/myshixuns/index.html.erb b/app/views/admins/myshixuns/index.html.erb
new file mode 100644
index 000000000..311c1003f
--- /dev/null
+++ b/app/views/admins/myshixuns/index.html.erb
@@ -0,0 +1,14 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('学员实训列表') %>
+<% end %>
+
+
+ <%= form_tag(admins_myshixuns_path, method: :get, class: 'form-inline search-form', remote: true) do %>
+ <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-md-4 ml-3', placeholder: '学员UID/姓名/学校/实训名称/老师姓名检索') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
+ <% end %>
+
+
+
+ <%= render(partial: 'admins/myshixuns/shared/list', locals: { myshixuns: @myshixuns, finish_game_count: @finish_game_count, total_score: @total_score }) %>
+
\ No newline at end of file
diff --git a/app/views/admins/myshixuns/index.js.erb b/app/views/admins/myshixuns/index.js.erb
new file mode 100644
index 000000000..454f0e02a
--- /dev/null
+++ b/app/views/admins/myshixuns/index.js.erb
@@ -0,0 +1 @@
+$('.myshixun-list-container').html("<%= j( render(partial: 'admins/myshixuns/shared/list', locals: { myshixuns: @myshixuns, finish_game_count: @finish_game_count, total_score: @total_score }) ) %>");
\ No newline at end of file
diff --git a/app/views/admins/myshixuns/shared/_list.html.erb b/app/views/admins/myshixuns/shared/_list.html.erb
new file mode 100644
index 000000000..78e42d58b
--- /dev/null
+++ b/app/views/admins/myshixuns/shared/_list.html.erb
@@ -0,0 +1,49 @@
+
+
+
+ ID
+ 标识
+ 实训名称
+ 实训老师
+ 完成
+ 经验值
+ 学员姓名
+ 学员单位
+ <%= sort_tag('开启时间', name: 'created_at', path: admins_myshixuns_path) %>
+
+
+
+ <% if myshixuns.present? %>
+ <% myshixuns.each do |myshixun| %>
+
+ <%= myshixun.id %>
+
+ <% current_task = myshixun.last_executable_task || myshixun.last_task %>
+ <%= link_to "/myshixuns/#{myshixun.identifier}/stages/#{current_task.identifier}", target: '_blank' do %>
+ <%= myshixun.identifier %>
+ <% end %>
+
+
+ <%= link_to "/shixuns/#{myshixun.shixun.identifier}", target: '_blank' do %>
+ <%= overflow_hidden_span myshixun.shixun.name, width: 280 %>
+ <% end %>
+
+ <%= myshixun.shixun.user.real_name %>
+ <%= finish_game_count.fetch(myshixun.id, 0) %>/<%= myshixun.shixun.challenges_count %>
+ <%= total_score.fetch(myshixun.id, 0) %>
+
+ <%= link_to "/users/#{myshixun.user.login}", target: '_blank' do %>
+ <%= overflow_hidden_span myshixun.user.real_name, width: 80 %>
+ <% end %>
+
+ <%= overflow_hidden_span myshixun.user&.school_name, width: 150 %>
+ <%= myshixun.created_at&.strftime('%Y-%m-%d %H:%M') %>
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: myshixuns } %>
\ 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 e10d2bd80..32eaa47bd 100644
--- a/app/views/admins/professional_authentications/index.html.erb
+++ b/app/views/admins/professional_authentications/index.html.erb
@@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '姓名/学校/单位检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
diff --git a/app/views/admins/project_package_applies/index.html.erb b/app/views/admins/project_package_applies/index.html.erb
new file mode 100644
index 000000000..912ea3e59
--- /dev/null
+++ b/app/views/admins/project_package_applies/index.html.erb
@@ -0,0 +1,32 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('众包需求发布') %>
+<% end %>
+
+
+
+
+ <%= render(partial: 'admins/project_package_applies/shared/list', locals: { applies: @package_applies}) %>
+
+
+<%= render(partial: 'admins/shared/admin_common_refuse_modal') %>
\ No newline at end of file
diff --git a/app/views/admins/project_package_applies/index.js.erb b/app/views/admins/project_package_applies/index.js.erb
new file mode 100644
index 000000000..fe4d5c782
--- /dev/null
+++ b/app/views/admins/project_package_applies/index.js.erb
@@ -0,0 +1 @@
+$('.project-package-applies-list-container').html("<%= j( render partial: 'admins/project_package_applies/shared/list', locals: { applies: @package_applies } ) %>");
\ No newline at end of file
diff --git a/app/views/admins/project_package_applies/shared/_list.html.erb b/app/views/admins/project_package_applies/shared/_list.html.erb
new file mode 100644
index 000000000..736d939f9
--- /dev/null
+++ b/app/views/admins/project_package_applies/shared/_list.html.erb
@@ -0,0 +1,56 @@
+<% is_processed = params[:status].to_s != 'pending' %>
+
+
+
+
+ 头像
+ 姓名
+ 众包需求
+ 需求描述
+ 时间
+ <% if is_processed %>
+ 拒绝原因
+ 状态
+ <% else %>
+ 操作
+ <% end %>
+
+
+
+ <% if applies.present? %>
+ <% applies.each do |apply| %>
+ <% package = apply.project_package %>
+ <% user = package.creator %>
+
+
+ <%= link_to "/users/#{user.login}", class: 'professional-authentication-avatar', target: '_blank', data: { toggle: 'tooltip', title: '个人主页' } do %>
+
+ <% end %>
+
+ <%= user.real_name %>
+ <%= 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 is_processed %>
+ <%= overflow_hidden_span apply.reason %>
+ <%= t("admins_apply_status.status.#{apply.status}") %>
+ <% else %>
+
+ <%= agree_link '同意', agree_admins_project_package_apply_path(apply, element: ".project_package_applies-#{apply.id}"), 'data-confirm': '确认审核通过?' %>
+ <%= javascript_void_link('拒绝', class: 'action refuse-action',
+ data: {
+ toggle: 'modal', target: '.admin-common-refuse-modal', id: apply.id,
+ url: refuse_admins_project_package_apply_path(apply, element: ".project_package_applies-#{apply.id}")
+ }) %>
+
+ <% end %>
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: applies } %>
\ No newline at end of file
diff --git a/app/views/admins/shared/403.html.erb b/app/views/admins/shared/403.html.erb
new file mode 100644
index 000000000..47e5e9038
--- /dev/null
+++ b/app/views/admins/shared/403.html.erb
@@ -0,0 +1,6 @@
+
\ No newline at end of file
diff --git a/app/views/admins/shared/500.html.erb b/app/views/admins/shared/500.html.erb
index f053f58ec..b1488d6ff 100644
--- a/app/views/admins/shared/500.html.erb
+++ b/app/views/admins/shared/500.html.erb
@@ -2,5 +2,5 @@
500
- 系统错误
+ <%= @message %>
\ No newline at end of file
diff --git a/app/views/admins/shared/_admin_common_refuse_modal.html.erb b/app/views/admins/shared/_admin_common_refuse_modal.html.erb
index a2daf7f0c..10baaef64 100644
--- a/app/views/admins/shared/_admin_common_refuse_modal.html.erb
+++ b/app/views/admins/shared/_admin_common_refuse_modal.html.erb
@@ -2,20 +2,20 @@
diff --git a/app/views/admins/shixun_settings/index.html.erb b/app/views/admins/shixun_settings/index.html.erb
new file mode 100644
index 000000000..8fd7a2526
--- /dev/null
+++ b/app/views/admins/shixun_settings/index.html.erb
@@ -0,0 +1,76 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('实训配置', admins_shixun_settings_path) %>
+<% end %>
+
+
+
+
+ <%= render partial: 'admins/shixun_settings/shared/list', locals: { shixun_settings: @shixun_settings } %>
+
+
+<%= render partial: 'admins/shared/modal/upload_file_modal', locals: { title: '上传图片' } %>
\ No newline at end of file
diff --git a/app/views/admins/shixun_settings/index.js.erb b/app/views/admins/shixun_settings/index.js.erb
new file mode 100644
index 000000000..af07e062a
--- /dev/null
+++ b/app/views/admins/shixun_settings/index.js.erb
@@ -0,0 +1 @@
+$(".shixun-settings-list-container").html("<%= j render partial: "admins/shixun_settings/shared/list",locals: {shixun_settings:@shixun_settings} %>")
\ No newline at end of file
diff --git a/app/views/admins/shixun_settings/shared/_list.html.erb b/app/views/admins/shixun_settings/shared/_list.html.erb
new file mode 100644
index 000000000..0235e5ef8
--- /dev/null
+++ b/app/views/admins/shixun_settings/shared/_list.html.erb
@@ -0,0 +1,35 @@
+
+
+ 序号
+ ID
+ 实训名称
+ 技术平台
+ 权限
+ 技术体系
+ 上传图片
+ 创建者
+ 关闭
+ 复制
+ 代码执行时间
+
+ 操作
+
+ ssh/隐藏/首页/跳关/隐藏目录
+
+
+
+
+ <% if shixun_settings.present? %>
+ <% shixun_settings.each_with_index do |shixun,index| %>
+
+ <% page_no = (@params_page.to_i - 1) * 20 + index + 1 %>
+ <%= render partial: "admins/shixun_settings/shared/td",locals: {shixun: shixun,page_no:page_no} %>
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: shixun_settings } %>
\ No newline at end of file
diff --git a/app/views/admins/shixun_settings/shared/_td.html.erb b/app/views/admins/shixun_settings/shared/_td.html.erb
new file mode 100644
index 000000000..efdec4f8d
--- /dev/null
+++ b/app/views/admins/shixun_settings/shared/_td.html.erb
@@ -0,0 +1,51 @@
+
<%= page_no %>
+
<%= shixun.identifier %>
+
+
+ <%= link_to overflow_hidden_span(shixun.name,width:160), "/shixuns/#{shixun.identifier}", :target => "_blank", :title => shixun.name %>
+
+
+
+ <%= display_text shixun.shixun_main_name %>
+
+
+ <% status_options = [['超级管理员', '0'], ["合作团队", "1"]] %>
+ <%= select_tag(:use_scope, options_for_select(status_options,shixun.use_scope),class:"form-control shixun-setting-form",data:{id:shixun.id}) %>
+
+
+ <%= select_tag(:tag_repertoires, options_for_select(@shixun_tags,shixun.tag_repertoires.pluck(:id)),multiple:true,class:"form-control shixun-setting-form",data:{id:shixun.id},id:"tags-chosen-#{shixun.id}") %>
+
+
+ <% imageExists = File.exist?(disk_filename("Shixun",shixun.id)) %>
+ <% imageUrl = imageExists ? '/' + url_to_avatar(shixun) + "?#{Time.now.to_i}" : '' %>
+ <%= 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' %>
+
+ <% if shixun.status.to_i < 3 %>
+ <%= link_to "关闭", admins_shixun_setting_path(shixun,status:3,page_no:page_no),method: :put, :class => "", :remote => true %>
+ <% else %>
+ 已关闭
+ <% end %>
+
+
+ <%= check_box_tag :can_copy,!shixun.can_copy,shixun.can_copy,remote:true,data:{id:shixun.id},class:"shixun-setting-form" %>
+
+
+
+
+
+ <%= check_box_tag :webssh,(shixun.webssh == 1 ? 0 : 1),(shixun.webssh == 1 ? true : false),remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form",title:"ssh" %>
+ <%= check_box_tag :hidden,!shixun.hidden,shixun.hidden,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"隐藏"%>
+ <%= check_box_tag :homepage_show,!shixun.homepage_show,shixun.homepage_show,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form",title:"首页" %>
+ <%= check_box_tag :task_pass,!shixun.task_pass,shixun.task_pass,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"跳关"%>
+ <%= check_box_tag :code_hidden,!shixun.code_hidden,shixun.code_hidden,remote:true,data:{id:shixun.id,toggle:"tooltip",placement:"top"},class:"shixun-setting-form" ,title:"隐藏目录"%>
+
+
+
\ No newline at end of file
diff --git a/app/views/admins/shixun_settings/update.js.erb b/app/views/admins/shixun_settings/update.js.erb
new file mode 100644
index 000000000..bd98a01af
--- /dev/null
+++ b/app/views/admins/shixun_settings/update.js.erb
@@ -0,0 +1 @@
+$("#setting-item-<%= @shixun.id %>").html("<%= j render partial: "admins/shixun_settings/shared/td",locals: {shixun: @shixun,page_no:@page_no} %>")
\ No newline at end of file
diff --git a/app/views/admins/shixuns/index.html.erb b/app/views/admins/shixuns/index.html.erb
new file mode 100644
index 000000000..92fa670ba
--- /dev/null
+++ b/app/views/admins/shixuns/index.html.erb
@@ -0,0 +1,32 @@
+<% define_admin_breadcrumbs do %>
+ <% add_admin_breadcrumb('实训列表', admins_shixuns_path) %>
+<% end %>
+
+
+ <%= form_tag(admins_shixuns_path, method: :get, class: 'form-inline search-form',id:"shixuns-search-form",remote:true) do %>
+
+ 状态:
+ <% status_options = [['全部', ''], ["编辑中(#{@editing_shixuns})", "editing"], ["待审核(#{@pending_shixuns})", 'pending'], ["已发布(#{@processed_shixuns})", 'processed'],["已关闭(#{@closed_shixuns})",'closed']] %>
+ <%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
+
+
+
+ 技术平台:
+ <%= select_tag(:tag, options_for_select(@shixuns_type_check.unshift(["",nil])), class: 'form-control',id:"tag-choosed") %>
+
+
+
+ 搜索类型:
+ <% auto_trial_options = [['创建者姓名', 0], ['实训名称', 1], ['学校名称', 2]] %>
+ <%= select_tag(:search_type, options_for_select(auto_trial_options), class: 'form-control') %>
+
+ <%= 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_shixuns_path,class: "btn btn-default",id:"shixuns-clear-search",'data-disable-with': '清除中...' %>
+<% end %>
+
导出
+
+
+
+ <%= render partial: 'admins/shixuns/shared/list', locals: { shixuns: @shixuns } %>
+
diff --git a/app/views/admins/shixuns/index.js.erb b/app/views/admins/shixuns/index.js.erb
new file mode 100644
index 000000000..a53098853
--- /dev/null
+++ b/app/views/admins/shixuns/index.js.erb
@@ -0,0 +1 @@
+$(".shixuns-list-container").html("<%= j render partial: "admins/shixuns/shared/list",locals: {shixuns:@shixuns} %>")
\ No newline at end of file
diff --git a/app/views/admins/shixuns/shared/_list.html.erb b/app/views/admins/shixuns/shared/_list.html.erb
new file mode 100644
index 000000000..64fb32d56
--- /dev/null
+++ b/app/views/admins/shixuns/shared/_list.html.erb
@@ -0,0 +1,55 @@
+
+
+ 序号
+ ID
+ 实训名称
+ 技术平台
+ Fork源
+ 实践
+ 选择
+ 状态
+ 创建者
+ <%= sort_tag('创建于', name: 'created_on', path: admins_shixuns_path) %>
+ 单测
+ 操作
+
+
+ <% if shixuns.present? %>
+ <% shixuns.each_with_index do |shixun,index| %>
+
+ <%= (@params_page.to_i - 1) * 20 + index + 1%>
+ <%= shixun.identifier %>
+ <%= link_to overflow_hidden_span(shixun.name), "/shixuns/#{shixun.identifier}", :target => "_blank", :title => shixun.name %>
+
+ <%= shixun.shixun_main_name.nil? ? "--" : shixun.shixun_main_name %>
+
+
+ <% if shixun.try(:fork_from).nil? %>
+ --
+ <% else%>
+ <%= link_to shixun.try(:identifier), shixun_path(shixun.try(:identifier)), target: '_blank'%>
+ <% end%>
+
+ <%= 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' %>
+ <%= format_time shixun.created_at %>
+
+ class="ml-3 mr5 magic-checkbox" id="join_teacher_homepage_<%= shixun.id %>">
+
+
+
+ <% if shixun.status == 0 %>
+ <%= link_to(l(:button_delete), admins_shixun_path(shixun), :method => :delete, :data => { confirm: "您确定要删除吗?" } ) %>
+ <% end %>
+
+
+ <% end %>
+ <% else %>
+ <%= render 'admins/shared/no_data_for_table' %>
+ <% end %>
+
+
+
+<%= render partial: 'admins/shared/paginate', locals: { objects: shixuns } %>
\ No newline at end of file
diff --git a/app/views/admins/subject_authorizations/index.html.erb b/app/views/admins/subject_authorizations/index.html.erb
index 3d5539663..522278a3d 100644
--- a/app/views/admins/subject_authorizations/index.html.erb
+++ b/app/views/admins/subject_authorizations/index.html.erb
@@ -21,7 +21,7 @@
<%= select_tag(:status, options_for_select(status_options), class: 'form-control') %>
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '实训课程名称检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
diff --git a/app/views/admins/users/edit.html.erb b/app/views/admins/users/edit.html.erb
index 3f9d71b96..22ac1f18e 100644
--- a/app/views/admins/users/edit.html.erb
+++ b/app/views/admins/users/edit.html.erb
@@ -131,7 +131,7 @@
<%= f.button :submit, value: '保存', class: 'btn-primary mr-3 px-4' %>
- <%= link_to '取消', 'javascript:history.go(-1)', class: 'btn btn-secondary px-4' %>
+ <%= link_to '取消', admins_users_path, class: 'btn btn-secondary px-4' %>
<% end %>
\ 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 5d2af36c3..b145edd24 100644
--- a/app/views/admins/users/index.html.erb
+++ b/app/views/admins/users/index.html.erb
@@ -24,7 +24,7 @@
<%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: 'ID/姓名/邮箱/手机号检索') %>
<%= text_field_tag(:school_name, params[:school_name], class: 'form-control col-sm-2', placeholder: '学校/单位检索') %>
- <%= submit_tag('搜索', class: 'btn btn-primary ml-3') %>
+ <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %>
<% end %>
diff --git a/app/views/admins/users/index.json.jbuilder b/app/views/admins/users/index.json.jbuilder
new file mode 100644
index 000000000..5591474a4
--- /dev/null
+++ b/app/views/admins/users/index.json.jbuilder
@@ -0,0 +1,6 @@
+json.count @users.total_count
+json.users do
+ json.array! @users.each do |user|
+ json.extract! user, :id, :login, :real_name, :identity, :school_name
+ end
+end
\ No newline at end of file
diff --git a/app/views/admins/users/shared/_reward_grade_modal.html.erb b/app/views/admins/users/shared/_reward_grade_modal.html.erb
index 87c74c499..2cf741906 100644
--- a/app/views/admins/users/shared/_reward_grade_modal.html.erb
+++ b/app/views/admins/users/shared/_reward_grade_modal.html.erb
@@ -2,7 +2,7 @@