diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 3e9601bf8..e7a4d28ff 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -83,4 +83,4 @@ $(document).on("turbolinks:before-cache", function () { // }); $(function () { -}); \ No newline at end of file +}); diff --git a/app/controllers/admins/import_course_members_controller.rb b/app/controllers/admins/import_course_members_controller.rb new file mode 100644 index 000000000..42022b710 --- /dev/null +++ b/app/controllers/admins/import_course_members_controller.rb @@ -0,0 +1,10 @@ +class Admins::ImportCourseMembersController < Admins::BaseController + def create + return render_error('请上传正确的文件') if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) + + result = Admins::ImportCourseMemberService.call(params[:file].to_io) + render_ok(result) + rescue Admins::ImportCourseMemberService::Error => ex + render_error(ex) + end +end \ No newline at end of file diff --git a/app/controllers/wechats/js_sdk_signatures_controller.rb b/app/controllers/wechats/js_sdk_signatures_controller.rb new file mode 100644 index 000000000..e4ee0da27 --- /dev/null +++ b/app/controllers/wechats/js_sdk_signatures_controller.rb @@ -0,0 +1,8 @@ +class Wechats::JsSdkSignaturesController < ApplicationController + def create + signature = Util::Wechat.js_sdk_signature(params[:url], params[:noncestr], params[:timestamp]) + render_ok(signature: signature) + rescue Util::Wechat::Error => ex + render_error(ex.message) + end +end \ No newline at end of file diff --git a/app/imports/admins/import_course_member_excel.rb b/app/imports/admins/import_course_member_excel.rb new file mode 100644 index 000000000..ddd3b01a1 --- /dev/null +++ b/app/imports/admins/import_course_member_excel.rb @@ -0,0 +1,20 @@ +class Admins::ImportCourseMemberExcel < BaseImportXlsx + Data = Struct.new(:student_id, :name, :course_id, :role, :course_group_name, :school_id) + + def read_each(&block) + sheet.each_row_streaming(pad_cells: true, offset: 1) do |row| + data = row.map(&method(:cell_value))[0..5] + block.call Data.new(*data) + end + end + + private + + def check_sheet_valid! + raise_import_error('请按照模板格式导入') if sheet.row(1).size != 6 + end + + def cell_value(obj) + obj&.cell_value&.to_s&.strip + end +end diff --git a/app/libs/util/wechat.rb b/app/libs/util/wechat.rb new file mode 100644 index 000000000..069322f18 --- /dev/null +++ b/app/libs/util/wechat.rb @@ -0,0 +1,74 @@ +module Util::Wechat + BASE_SITE = 'https://api.weixin.qq.com'.freeze + + Error = Class.new(StandardError) + + class << self + attr_accessor :appid, :secret + + def js_sdk_signature(url, noncestr, timestamp) + str = { jsapi_ticket: jsapi_ticket, noncestr: noncestr, timestamp: timestamp, url: url }.to_query + Digest::SHA1.hexdigest(str) + end + + def access_token + # 7200s 有效时间 + Rails.cache.fetch(access_token_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/token', appid: appid, secret: secret, grant_type: 'client_credential') + result['access_token'] + end + end + + def refresh_access_token + Rails.cache.delete(access_token_cache_key) + access_token + end + + def jsapi_ticket + # 7200s 有效时间 + Rails.cache.fetch(jsapi_ticket_cache_key, expires_in: 100.minutes) do + result = request(:get, '/cgi-bin/ticket/getticket', access_token: access_token, type: 'jsapi') + result['ticket'] + end + end + + def refresh_jsapi_ticket + Rails.cache.delete(jsapi_ticket_cache_key) + jsapi_ticket + end + + def access_token_cache_key + "#{base_cache_key}/access_token" + end + + def jsapi_ticket_cache_key + "#{base_cache_key}/jsapi_ticket" + end + + def base_cache_key + "wechat/#{appid}" + end + + private + + def request(method, url, **params) + Rails.logger.error("[wechat] request: #{method} #{url} #{params.inspect}") + + client = Faraday.new(url: BASE_SITE) + response = client.public_send(method, url, params) + result = JSON.parse(response.body) + + Rails.logger.error("[wechat] response:#{response.status} #{result.inspect}") + + if response.status != 200 + raise Error, result.inspect + end + + if result['errcode'].present? && result['errcode'].to_i.nonzero? + raise Error, result.inspect + end + + result + end + end +end \ No newline at end of file diff --git a/app/services/admins/import_course_member_service.rb b/app/services/admins/import_course_member_service.rb new file mode 100644 index 000000000..8f162902f --- /dev/null +++ b/app/services/admins/import_course_member_service.rb @@ -0,0 +1,63 @@ +class Admins::ImportCourseMemberService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :file, :result + + def initialize(file) + @file = file + @result = { success: 0, fail: [] } + end + + def call + raise Error, '文件不存在' if file.blank? + + excel = Admins::ImportCourseMemberExcel.new(file) + excel.read_each(&method(:create_course_member)) + + result + rescue ApplicationImport::Error => ex + raise Error, ex.message + end + + private + + def create_course_member(data) + raise '课堂角色必须为 2、3、4' unless [2, 3, 4].include?(data.role.to_i) + + user = User.joins(:user_extension).where(user_extensions: { student_id: data.student_id, school_id: data.school_id }).first + raise '该学号的用户不存在' if user.blank? + course = Course.find_by(id: data.course_id) + raise '该课堂不存在' if course.blank? + + course_group = nil + if data.course_group_name.present? + course_group = course.course_groups.find_or_create_by!(name: data.course_group_name) + end + + member = course.course_members.find_by(user_id: user.id, role: data.role.to_i) + # 如果已是课堂成员且是学生身份and不在指定的分班则移动到该分班 + if member.present? && member.role == :STUDENT && course_group && member.course_group_id != course_group&.id + member.update!(course_group_id: course_group&.id) + elsif member.blank? + course.course_members.create!(user_id: user.id, role: data.role.to_i, course_group_id: course_group&.id) + extra = + case data.role.to_i + when 2 then 9 + when 3 then 7 + else 10 + end + + Tiding.create!(user_id: user.id, trigger_user_id: course.tea_id, container_id: course.id, + container_type: 'TeacherJoinCourse', belong_container_id: course.id, + belong_container_type: 'Course', tiding_type: 'System', extra: extra) + end + + result[:success] += 1 + rescue Exception => ex + fail_data = data.as_json + fail_data[:data] = fail_data.values.join(',') + fail_data[:message] = ex.message + + result[:fail] << fail_data + end +end \ No newline at end of file diff --git a/config/configuration.yml.example b/config/configuration.yml.example index 2a4f4f017..6feee28d9 100644 --- a/config/configuration.yml.example +++ b/config/configuration.yml.example @@ -6,6 +6,9 @@ defaults: &defaults cate_id: '-1' callback_url: 'http://47.96.87.25:48080/api/callbacks/aliyun_vod.json' signature_key: 'test12345678' + wechat: + appid: 'test' + secret: 'test' development: <<: *defaults diff --git a/config/initializers/aliyun_vod_init.rb b/config/initializers/aliyun_vod_init.rb index 47b1dc6a3..9185eac20 100644 --- a/config/initializers/aliyun_vod_init.rb +++ b/config/initializers/aliyun_vod_init.rb @@ -4,7 +4,7 @@ aliyun_vod_config = {} begin config = Rails.application.config_for(:configuration) aliyun_vod_config = config['aliyun_vod'] - raise 'oauth wechat config missing' if aliyun_vod_config.blank? + raise 'aliyun vod config missing' if aliyun_vod_config.blank? rescue => ex raise ex if Rails.env.production? diff --git a/config/initializers/util_wechat_init.rb b/config/initializers/util_wechat_init.rb new file mode 100644 index 000000000..cb39afcaf --- /dev/null +++ b/config/initializers/util_wechat_init.rb @@ -0,0 +1,16 @@ +wechat_config = {} + +begin + config = Rails.application.config_for(:configuration) + wechat_config = config['wechat'] + raise 'wechat config missing' if wechat_config.blank? +rescue => ex + raise ex if Rails.env.production? + + puts %Q{\033[33m [warning] wechat config or configuration.yml missing, + please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} + wechat_config = {} +end + +Util::Wechat.appid = wechat_config['appid'] +Util::Wechat.secret = wechat_config['secret'] diff --git a/config/routes.rb b/config/routes.rb index c2da5fc63..27d5c4488 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,892 +1,897 @@ -Rails.application.routes.draw do - - require 'sidekiq/web' - require 'admin_constraint' - mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new - - get 'attachments/download/:id', to: 'attachments#show' - get 'attachments/download/:id/:filename', to: 'attachments#show' - - resources :edu_settings - scope '/api' do - get 'home/index' - get 'home/search' - - get 'search', to: 'searchs#index' - - post 'praise_tread/like', to: 'praise_tread#like' - delete 'praise_tread/unlike', to: 'praise_tread#unlike' - - put 'commons/hidden', to: 'commons#hidden' - put 'commons/unhidden', to: 'commons#unhidden' - delete 'commons/delete', to: 'commons#delete' - - resources :memos do - member do - post :sticky_or_cancel - post :hidden - get :more_reply - end - - collection do - post :reply - end - end - - resources :tem_tests - # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html - # - # - resources :accounts do - - collection do - post :login - post :register - post :reset_password - get :logout - get :get_verification_code - get :valid_email_and_phone - end - - end - - resources :users do - member do - get :homepage_info - end - - scope module: :users do - resources :courses, only: [:index] - resources :shixuns, only: [:index] - resources :projects, only: [:index] - resources :subjects, only: [:index] - resources :question_banks, only: [:index] - resource :experience_records, only: [:show] - resource :grade_records, only: [:show] - resource :watch, only: [:create, :destroy] - resources :project_packages, only: [:index] - # 私信 - resources :private_messages, only: [:index, :create, :destroy] - resources :recent_contacts, only: [:index] - resource :private_message_details, only: [:show] - resource :unread_message_info, only: [:show] - - # 视频 - resources :videos, only: [:index, :update] do - collection do - get :review - post :batch_publish - post :cancel - end - end - resource :video_auths, only: [:create, :update] - end - - - collection do - post :following - post :unfollow - get :get_user_info - get :attachment_show - get :html_show - get :get_navigation_info - post :reply_message - get :search_user_projects - post :brief_introduction - post :attendance - get :system_update - - resource :trial_apply, only: [:create] - resources :projects, module: :users, only: [] do - get :search, on: :collection - end - - resources :tidings, only: [:index] - - scope module: :users do - resource :interest, only: [:create] - - resources :accounts, only: [:show, :update] do - resource :phone_bind, only: [:create] - resource :email_bind, only: [:create] - resource :password, only: [:update] - resource :avatar, only: [:update] - resource :auth_attachment, only: [:create] - resource :authentication_apply, only: [:create] - resource :professional_auth_apply, only: [:create] - end - end - end - end - resources :users_for_private_messages, only: [:index] - - resources :myshixuns, param: :identifier, shallow: true do - member do - post :repository - post :commits - post :file_content - post :update_file - get :reset_my_game - post :html_content - get :open_webssh - get :challenges - end - collection do - get :sigle_mul_test - match :training_task_status, :via => [:get, :post] - match :code_runinng_message, :via => [:get, :post] - end - resources :games - end - - resources :games, path: :tasks, param: :identifier do - member do - get :star - get :git_entries - get :answer - get :answer_grade - get :rep_content - get :reset_original_code - get :reset_passed_code - post :file_update - post :choose_build - get :game_build - get :game_status - post :plus_or_cancel_praise - get :cost_time - get :system_update - get :sync_modify_time - get :picture_display - get :sync_codes - get :close_webssh - get :get_answer_info - get :unlock_answer - get :check_test_sets - get :unlock_choose_answer - get :get_choose_answer - - end - collection do - get :challenges - end - end - - resources :shixuns, param: :identifier do - collection do - get :menus - get :get_recommend_shixuns - get :departments - get :get_mirror_script - post :apply_shixun_mirror - get :download_file - end - - member do - post :copy - get :propaedeutics - get :show_right - get :operation - get :ranking_list - get :discusses - get :tasks - get :collaborators - get :settings - get :get_script_contents - get :get_custom_script - post :repository - post :commits - post :file_content - post :update_file - post :close - post :add_file - get :fork_list - post :update_propaedeutics - get :add_collaborators - post :shixun_members_added - match :change_manager, :via => [:get, :post] - get :search_user_courses - post :send_to_course - delete :collaborators_delete - get :cancel_publish - get :publish - get :shixun_exec - end - - resources :challenges do - member do - get 'index_up' - get 'index_down' - post 'create_choose_question' - get 'show_choose_question' - match 'choose_type_show', :via => [:get, :post] - match 'edit_choose_question', :via => [:get, :post] - match 'update_choose_question', :via => [:get, :post] - delete 'destroy_challenge_choose' - post :crud_answer - get :answer - - end - end - - resources :repositories do - collection do - post :add_project - post :fork_project - - post :file_tree # 目录树 - post :update_file # 文件更新 - post :file_content # 文件内容 - - post :commits # 提交记录 - end - end - end - - resources :discusses do - collection do - get :new_message - get :forum_discusses - end - - member do - post :reply - post :hidden - post :reward_code - post :plus - end - end - - resources :subjects, path: :paths do - member do - get 'choose_subject_shixun' - get 'publish' - get 'cancel_publish' - get 'cancel_has_publish' - get 'statistics' - get 'shixun_report' - get 'school_report' - post 'update_attr' - post :search_members - post 'add_subject_members' - delete 'delete_member' - get :choose_course - post 'send_to_course' - delete :delete_member - post :up_member_position - post :down_member_position - get :right_banner - end - - collection do - get 'create_subject' - get 'new_subject' - post 'append_to_stage' - get 'search' - end - end - - resources :stages do - member do - get 'down_position' - get 'up_position' - end - end - - resources :files, only: [:index, :show, :update] do - collection do - delete :bulk_delete - put :bulk_move - post :bulk_send - put :bulk_public - get :public_with_course_and_project - get :mine_with_course_and_project - post :import - post :upload - put :bulk_publish - end - member do - get :histories - end - end - - resources :courses do - member do - get 'settings', :action => 'settings', :as => 'settings' - post 'set_invite_code_halt' - post 'set_public_or_private' - post 'search_teacher_candidate' - post 'add_teacher' - post 'create_graduation_group' - post 'join_graduation_group' - post 'set_course_group' - post 'change_course_admin' - post 'change_course_teacher' - post 'delete_course_teacher' - post 'teacher_application_review' - post 'transfer_to_course_group' - post 'delete_from_course' - post 'add_students_by_search' - post 'create_group_by_importing_file' - post 'duplicate_course' - post 'visits_plus_one' - get 'get_historical_courses' - get 'get_historical_course_students' - get 'course_group_list' - get 'add_teacher_popup' - get 'teachers' - get 'apply_teachers' - get 'graduation_group_list' - get 'top_banner' - get 'left_banner' - get 'students' - get 'all_course_groups' - get 'search_users' - get 'base_info' - get 'attahcment_category_list' - get 'export_member_scores_excel' #导出课堂信息 - get 'export_couser_info' - get 'export_member_act_score' - post 'switch_to_teacher' - post 'switch_to_assistant' - post 'switch_to_student' - post 'exit_course' - get 'informs' - post 'update_informs' - post 'new_informs' - get 'online_learning' - post 'join_excellent_course' - get 'tasks_list' - post 'update_task_position' - end - - collection do - post 'apply_to_join_course' - post 'search_course_list' - get 'board_list' - get 'mine' - get 'search_slim' - end - - resources :polls, only:[:index,:new,:create] do - collection do - post :publish # 立即发布 - post :end_poll # 立即截止 - post :destroys # 多个删除 - post :set_public # 设置公开 - post :join_poll_banks # 加入习题集 - get :my_polls #我的问卷题库 - get :public_polls # 公共问卷题库 - get :publish_modal # 立即发布弹窗内容 - get :end_poll_modal # 立即截止弹窗内容 - end - end - - resources :homework_commons, shallow: true do - - member do - get :group_list - post :homework_code_repeat - get :code_review_results - get :code_review_detail - post :update_explanation - get :show_comment - get :settings - post :update_settings - match 'works_list', :via => [:get, :post] - # post :works_list - get :reference_answer - get :publish_groups - get :end_groups - post :alter_name - get :update_score - get :update_student_score - end - - collection do - post 'create_shixun_homework' - match 'shixuns', via: [:get, :post] - match 'subjects', via: [:get, :post] - post 'create_subject_homework' - post 'publish_homework' - post 'end_homework' - post 'set_public' - post 'move_to_category' - get 'choose_category' - post 'multi_destroy' - post 'add_to_homework_bank' - end - - resources :student_works do - member do - get :shixun_work - get :shixun_work_report - post :adjust_review_score - get :commit_des - post :update_des - post :adjust_score - post :add_score - post :add_score_reply - delete :destroy_score - delete :destroy_score_reply - get :comment_list - get :supply_attachments - post :revise_attachment - delete :destroy_score - post :appeal_anonymous_score - post :deal_appeal_score - post :cancel_appeal - get :export_shixun_work_report - end - - collection do - get :search_member_list - get :check_project - get :cancel_relate_project - post :relate_project - delete :delete_work - end - end - end - - - resources :boards, shallow: true do - resources :messages do - collection do - delete :bulk_delete - put :bulk_move - post :bulk_send - put :bulk_public - end - - member do - get :reply_list - put :sticky_top - post :reply - end - end - member do - post 'move_category' - end - end - - resources :exercises ,only:[:index,:new,:create] do - collection do - get :my_exercises #我的试卷题库 - get :public_exercises # 公共试卷题库 - get :publish_modal # 立即发布弹窗内容 - get :end_modal # 立即截止弹窗内容 - post :destroys - post :set_public # 设置公开 - post :join_exercise_banks # 加入习题集 - post :publish # 立即发布 - post :end_exercise # 立即截止 - - end - end - - resources :course_groups, shallow: true do - member do - post 'rename_group' - post 'move_category' - end - - collection do - end - end - - resources :graduation_topics do - member do - post :refuse_student_topic - post :accept_student_topic - post :student_select_topic - post :student_cancel_topic - get :show_detail - get :show_comment - end - collection do - delete :destroys - post :set_public - get :export - post :add_to_bank - end - end - - resources :graduation_tasks, shallow: true do - resources :graduation_works do - collection do - post 'search_member_list' - get 'check_project' - post 'relate_project' - get 'cancel_relate_project' - post 'revise_attachment' - end - - member do - get 'comment_list' - post 'add_score' - post 'adjust_score' - delete 'delete_score' - get 'supply_attachments' - post 'revise_attachment' - post :assign_teacher - end - end - member do - get 'settings' - post 'update_settings' - get 'tasks_list' - get :show_comment - end - - collection do - post 'set_public' - delete 'multi_destroy' - post 'publish_task' - post 'end_task' - post 'add_to_bank' - end - end - end - - resources :polls,except:[:index,:new,:create] do - member do - get :poll_setting - post :commit_setting - get :start_answer - post :commit_poll - get :commit_result - get :poll_lists # 问卷的答题列表 - post :cancel_publish #撤销发布 - get :cancel_publish_modal #撤销发布的弹窗 - get :common_header - end - resources :poll_questions,only:[:new,:create] - end - - resources :poll_questions,except:[:new,:create,:index] do - member do - post :delete_answer - post :up_down - post :commit_answer - end - resource :poll_votes,only:[:create,:destroy] - end - - resources :exercises do - member do - get :choose_shixun - get :commit_shixun - get :exercise_setting - post :commit_setting - get :start_answer - post :commit_exercise - get :redo_modal #打回重做弹窗内容 - post :redo_exercise - get :review_exercise - get :exercise_lists - # get :blank_exercise #摒弃,仅作为测试html页面才会使用 - get :export_exercise - get :common_header - get :exercise_result - post :cancel_exercise - get :begin_commit #提交前的弹窗 - end - resources :exercise_questions,only:[:new,:create,:index] - end - - resources :exercise_questions,except:[:new,:create,:index] do - member do - post :up_down - post :delete_answer - post :adjust_score - post :update_scores - end - resource :exercise_answers,only:[:create,:destroy] - end - - - resources :course_modules, shallow: true do - member do - get 'sticky_module' - get 'hidden_module' - post 'rename_module' - post 'add_second_category' - end - collection do - post 'unhidden_modules' - end - end - - resources :course_second_categories, shallow: true do - member do - post 'rename_category' - post 'move_category' - end - collection do - - end - end - - resources :question_banks do - collection do - get :bank_list - post :save_banks - get :my_courses - post :send_to_course - delete :multi_delete - post :multi_public - end - end - - resources :homework_banks do - member do - post :set_public - end - end - - resources :gtopic_banks - resources :task_banks - - resources :exercise_banks do - collection do - get :choose_shixun - end - - member do - get :commit_shixun - end - end - - resources :exercise_bank_questions do - member do - post :up_down - get :choose_shixun - end - end - - resources :poll_bank_questions - - resources :attachments - - resources :schools do - member do - resources :departments, only: [] do - get :for_option, on: :collection - end - end - collection do - get :school_list - get :for_option - end - - scope module: :ecs do - get :detail, to: 'homes#index' - - resources :ec_majors, only: [:index] - resources :ec_major_schools, only: [:index, :create, :destroy] - end - end - resources :add_school_applies, only: [:create] - resources :add_department_applies, only: [:create] - - # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 - scope module: :ecs do - resources :ec_major_schools, only: [] do - resources :major_managers, only: [:create, :destroy] - resources :ec_years, only: [:index, :create, :destroy] - end - - resources :ec_years, only: [] do - resource :ec_training_objectives, only: [:show, :create] - resources :ec_graduation_requirements, only: [:index, :create] - resource :requirement_support_objectives, only: [:show, :create, :destroy] - resource :subitem_support_standards, only: [:show, :create, :destroy] - resource :students, only: [:show, :destroy] do - post :import, on: :collection - end - - resources :ec_courses, only: [:index, :create, :destroy] do - post :link_course, on: :member - - collection do - post :import - get :search - end - end - - resource :graduation_course_supports, only: [:show, :create] - resource :reach_evaluation, only: [:show, :create] - resource :reach_criteria, only: [:create] - end - - resources :ec_courses, only: [] do - resource :evaluation, only: [:show, :create] - resources :course_managers, only: [:create, :destroy] - resources :course_targets, only: [:index, :create] do - get :with_achievement_methods, on: :collection - - resource :course_achievement_methods, only: [:create] - end - resources :course_evaluations, only: [:index, :create, :update, :destroy] do - member do - get :average_score_import_template - get :detail_score_import_template - get :import_student_achievement - end - get :slimmer, on: :collection - end - resource :score_levels, only: [:show, :create] - end - end - - resource :zip, only: [] do - collection do - get :shixun_report - get :export_exercises - end - end - - resources :repertoires, only: [:index] - - scope module: :competitions do - resources :competitions, only: [:index, :show] do - resources :competition_modules, only: [:index, :show, :update] - resource :competition_staff - resources :competition_teams, only: [:index, :show] do - post :join, on: :collection - post :leave, on: :member - end - resources :teachers, only: [:index] - resources :students, only: [:index] - end - end - - resources :project_package_categories, only: [:index] - resources :project_packages, only: [:index, :show, :create, :update, :destroy] do - resources :bidding_users, only: [:create] do - post :win, on: :collection - end - end - - resources :libraries, only: [:index, :show, :create, :update, :destroy] - - scope module: :projects do - resources :project_applies, only: [:create] - end - - post 'callbacks/aliyun_vod', to: 'callbacks/aliyun_vods#create' - end - - namespace :admins do - get '/', to: 'dashboards#index' - resources :dashboards, only: [:index] do - collection do - get :month_active_user - get :evaluate - end - end - resources :files, only: [:create] - - resources :daily_school_statistics, only: [:index] do - get :export, on: :collection - end - - resources :school_statistics, only: [:index] do - get :contrast, on: :collection - end - - resources :users, only: [:index, :edit, :update, :destroy] do - member do - post :reward_grade - post :lock - post :unlock - post :active - end - end - resource :import_users, only: [:create] - - resources :library_applies, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :video_applies, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :identity_authentications, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :professional_authentications, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :shixun_authorizations, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :subject_authorizations, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :project_package_applies, only: [:index] do - member do - post :agree - post :refuse - end - end - resources :shixuns, only: [:index,:destroy] - resources :shixun_settings, only: [:index,:update] - resources :mirror_repositories, only: [:index, :new, :create, :edit, :update, :destroy] do - collection do - post :merge - get :for_select - end - - resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy] - end - resources :choose_mirror_repositories, only: [:new, :create] - resources :departments, only: [:index, :create, :edit, :update, :destroy] do - resource :department_member, only: [:create, :update, :destroy] - - post :merge, on: :collection - end - resources :myshixuns, only: [:index] - end - - resources :colleges, only: [] do - member do - get :statistics - get :course_statistics - get :student_shixun - get :shixun_time - get :shixun_report_count - get :teachers - get :shixun_chart_data - get :student_hot_evaluations - end - end - - #git 认证回调 - match 'gitauth/*url', to: 'gits#auth', via: :all - - get 'oauth/get_code', to: 'oauth#get_code' - get 'oauth/get_token_callback', to: 'oauth#get_token_callback' - - root 'main#index' - - ## react用 - get '*path', to: 'main#index', constraints: ReactConstraint.new -end +Rails.application.routes.draw do + + require 'sidekiq/web' + require 'admin_constraint' + mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new + + get 'attachments/download/:id', to: 'attachments#show' + get 'attachments/download/:id/:filename', to: 'attachments#show' + + resources :edu_settings + scope '/api' do + get 'home/index' + get 'home/search' + + get 'search', to: 'searchs#index' + + post 'praise_tread/like', to: 'praise_tread#like' + delete 'praise_tread/unlike', to: 'praise_tread#unlike' + + put 'commons/hidden', to: 'commons#hidden' + put 'commons/unhidden', to: 'commons#unhidden' + delete 'commons/delete', to: 'commons#delete' + + resources :memos do + member do + post :sticky_or_cancel + post :hidden + get :more_reply + end + + collection do + post :reply + end + end + + resources :tem_tests + # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html + # + # + resources :accounts do + + collection do + post :login + post :register + post :reset_password + get :logout + get :get_verification_code + get :valid_email_and_phone + end + + end + + resources :users do + member do + get :homepage_info + end + + scope module: :users do + resources :courses, only: [:index] + resources :shixuns, only: [:index] + resources :projects, only: [:index] + resources :subjects, only: [:index] + resources :question_banks, only: [:index] + resource :experience_records, only: [:show] + resource :grade_records, only: [:show] + resource :watch, only: [:create, :destroy] + resources :project_packages, only: [:index] + # 私信 + resources :private_messages, only: [:index, :create, :destroy] + resources :recent_contacts, only: [:index] + resource :private_message_details, only: [:show] + resource :unread_message_info, only: [:show] + + # 视频 + resources :videos, only: [:index, :update] do + collection do + get :review + post :batch_publish + post :cancel + end + end + resource :video_auths, only: [:create, :update] + end + + + collection do + post :following + post :unfollow + get :get_user_info + get :attachment_show + get :html_show + get :get_navigation_info + post :reply_message + get :search_user_projects + post :brief_introduction + post :attendance + get :system_update + + resource :trial_apply, only: [:create] + resources :projects, module: :users, only: [] do + get :search, on: :collection + end + + resources :tidings, only: [:index] + + scope module: :users do + resource :interest, only: [:create] + + resources :accounts, only: [:show, :update] do + resource :phone_bind, only: [:create] + resource :email_bind, only: [:create] + resource :password, only: [:update] + resource :avatar, only: [:update] + resource :auth_attachment, only: [:create] + resource :authentication_apply, only: [:create] + resource :professional_auth_apply, only: [:create] + end + end + end + end + resources :users_for_private_messages, only: [:index] + + resources :myshixuns, param: :identifier, shallow: true do + member do + post :repository + post :commits + post :file_content + post :update_file + get :reset_my_game + post :html_content + get :open_webssh + get :challenges + end + collection do + get :sigle_mul_test + match :training_task_status, :via => [:get, :post] + match :code_runinng_message, :via => [:get, :post] + end + resources :games + end + + resources :games, path: :tasks, param: :identifier do + member do + get :star + get :git_entries + get :answer + get :answer_grade + get :rep_content + get :reset_original_code + get :reset_passed_code + post :file_update + post :choose_build + get :game_build + get :game_status + post :plus_or_cancel_praise + get :cost_time + get :system_update + get :sync_modify_time + get :picture_display + get :sync_codes + get :close_webssh + get :get_answer_info + get :unlock_answer + get :check_test_sets + get :unlock_choose_answer + get :get_choose_answer + + end + collection do + get :challenges + end + end + + resources :shixuns, param: :identifier do + collection do + get :menus + get :get_recommend_shixuns + get :departments + get :get_mirror_script + post :apply_shixun_mirror + get :download_file + end + + member do + post :copy + get :propaedeutics + get :show_right + get :operation + get :ranking_list + get :discusses + get :tasks + get :collaborators + get :settings + get :get_script_contents + get :get_custom_script + post :repository + post :commits + post :file_content + post :update_file + post :close + post :add_file + get :fork_list + post :update_propaedeutics + get :add_collaborators + post :shixun_members_added + match :change_manager, :via => [:get, :post] + get :search_user_courses + post :send_to_course + delete :collaborators_delete + get :cancel_publish + get :publish + get :shixun_exec + end + + resources :challenges do + member do + get 'index_up' + get 'index_down' + post 'create_choose_question' + get 'show_choose_question' + match 'choose_type_show', :via => [:get, :post] + match 'edit_choose_question', :via => [:get, :post] + match 'update_choose_question', :via => [:get, :post] + delete 'destroy_challenge_choose' + post :crud_answer + get :answer + + end + end + + resources :repositories do + collection do + post :add_project + post :fork_project + + post :file_tree # 目录树 + post :update_file # 文件更新 + post :file_content # 文件内容 + + post :commits # 提交记录 + end + end + end + + resources :discusses do + collection do + get :new_message + get :forum_discusses + end + + member do + post :reply + post :hidden + post :reward_code + post :plus + end + end + + resources :subjects, path: :paths do + member do + get 'choose_subject_shixun' + get 'publish' + get 'cancel_publish' + get 'cancel_has_publish' + get 'statistics' + get 'shixun_report' + get 'school_report' + post 'update_attr' + post :search_members + post 'add_subject_members' + delete 'delete_member' + get :choose_course + post 'send_to_course' + delete :delete_member + post :up_member_position + post :down_member_position + get :right_banner + end + + collection do + get 'create_subject' + get 'new_subject' + post 'append_to_stage' + get 'search' + end + end + + resources :stages do + member do + get 'down_position' + get 'up_position' + end + end + + resources :files, only: [:index, :show, :update] do + collection do + delete :bulk_delete + put :bulk_move + post :bulk_send + put :bulk_public + get :public_with_course_and_project + get :mine_with_course_and_project + post :import + post :upload + put :bulk_publish + end + member do + get :histories + end + end + + resources :courses do + member do + get 'settings', :action => 'settings', :as => 'settings' + post 'set_invite_code_halt' + post 'set_public_or_private' + post 'search_teacher_candidate' + post 'add_teacher' + post 'create_graduation_group' + post 'join_graduation_group' + post 'set_course_group' + post 'change_course_admin' + post 'change_course_teacher' + post 'delete_course_teacher' + post 'teacher_application_review' + post 'transfer_to_course_group' + post 'delete_from_course' + post 'add_students_by_search' + post 'create_group_by_importing_file' + post 'duplicate_course' + post 'visits_plus_one' + get 'get_historical_courses' + get 'get_historical_course_students' + get 'course_group_list' + get 'add_teacher_popup' + get 'teachers' + get 'apply_teachers' + get 'graduation_group_list' + get 'top_banner' + get 'left_banner' + get 'students' + get 'all_course_groups' + get 'search_users' + get 'base_info' + get 'attahcment_category_list' + get 'export_member_scores_excel' #导出课堂信息 + get 'export_couser_info' + get 'export_member_act_score' + post 'switch_to_teacher' + post 'switch_to_assistant' + post 'switch_to_student' + post 'exit_course' + get 'informs' + post 'update_informs' + post 'new_informs' + get 'online_learning' + post 'join_excellent_course' + get 'tasks_list' + post 'update_task_position' + end + + collection do + post 'apply_to_join_course' + post 'search_course_list' + get 'board_list' + get 'mine' + get 'search_slim' + end + + resources :polls, only:[:index,:new,:create] do + collection do + post :publish # 立即发布 + post :end_poll # 立即截止 + post :destroys # 多个删除 + post :set_public # 设置公开 + post :join_poll_banks # 加入习题集 + get :my_polls #我的问卷题库 + get :public_polls # 公共问卷题库 + get :publish_modal # 立即发布弹窗内容 + get :end_poll_modal # 立即截止弹窗内容 + end + end + + resources :homework_commons, shallow: true do + + member do + get :group_list + post :homework_code_repeat + get :code_review_results + get :code_review_detail + post :update_explanation + get :show_comment + get :settings + post :update_settings + match 'works_list', :via => [:get, :post] + # post :works_list + get :reference_answer + get :publish_groups + get :end_groups + post :alter_name + get :update_score + get :update_student_score + end + + collection do + post 'create_shixun_homework' + match 'shixuns', via: [:get, :post] + match 'subjects', via: [:get, :post] + post 'create_subject_homework' + post 'publish_homework' + post 'end_homework' + post 'set_public' + post 'move_to_category' + get 'choose_category' + post 'multi_destroy' + post 'add_to_homework_bank' + end + + resources :student_works do + member do + get :shixun_work + get :shixun_work_report + post :adjust_review_score + get :commit_des + post :update_des + post :adjust_score + post :add_score + post :add_score_reply + delete :destroy_score + delete :destroy_score_reply + get :comment_list + get :supply_attachments + post :revise_attachment + delete :destroy_score + post :appeal_anonymous_score + post :deal_appeal_score + post :cancel_appeal + get :export_shixun_work_report + end + + collection do + get :search_member_list + get :check_project + get :cancel_relate_project + post :relate_project + delete :delete_work + end + end + end + + + resources :boards, shallow: true do + resources :messages do + collection do + delete :bulk_delete + put :bulk_move + post :bulk_send + put :bulk_public + end + + member do + get :reply_list + put :sticky_top + post :reply + end + end + member do + post 'move_category' + end + end + + resources :exercises ,only:[:index,:new,:create] do + collection do + get :my_exercises #我的试卷题库 + get :public_exercises # 公共试卷题库 + get :publish_modal # 立即发布弹窗内容 + get :end_modal # 立即截止弹窗内容 + post :destroys + post :set_public # 设置公开 + post :join_exercise_banks # 加入习题集 + post :publish # 立即发布 + post :end_exercise # 立即截止 + + end + end + + resources :course_groups, shallow: true do + member do + post 'rename_group' + post 'move_category' + end + + collection do + end + end + + resources :graduation_topics do + member do + post :refuse_student_topic + post :accept_student_topic + post :student_select_topic + post :student_cancel_topic + get :show_detail + get :show_comment + end + collection do + delete :destroys + post :set_public + get :export + post :add_to_bank + end + end + + resources :graduation_tasks, shallow: true do + resources :graduation_works do + collection do + post 'search_member_list' + get 'check_project' + post 'relate_project' + get 'cancel_relate_project' + post 'revise_attachment' + end + + member do + get 'comment_list' + post 'add_score' + post 'adjust_score' + delete 'delete_score' + get 'supply_attachments' + post 'revise_attachment' + post :assign_teacher + end + end + member do + get 'settings' + post 'update_settings' + get 'tasks_list' + get :show_comment + end + + collection do + post 'set_public' + delete 'multi_destroy' + post 'publish_task' + post 'end_task' + post 'add_to_bank' + end + end + end + + resources :polls,except:[:index,:new,:create] do + member do + get :poll_setting + post :commit_setting + get :start_answer + post :commit_poll + get :commit_result + get :poll_lists # 问卷的答题列表 + post :cancel_publish #撤销发布 + get :cancel_publish_modal #撤销发布的弹窗 + get :common_header + end + resources :poll_questions,only:[:new,:create] + end + + resources :poll_questions,except:[:new,:create,:index] do + member do + post :delete_answer + post :up_down + post :commit_answer + end + resource :poll_votes,only:[:create,:destroy] + end + + resources :exercises do + member do + get :choose_shixun + get :commit_shixun + get :exercise_setting + post :commit_setting + get :start_answer + post :commit_exercise + get :redo_modal #打回重做弹窗内容 + post :redo_exercise + get :review_exercise + get :exercise_lists + # get :blank_exercise #摒弃,仅作为测试html页面才会使用 + get :export_exercise + get :common_header + get :exercise_result + post :cancel_exercise + get :begin_commit #提交前的弹窗 + end + resources :exercise_questions,only:[:new,:create,:index] + end + + resources :exercise_questions,except:[:new,:create,:index] do + member do + post :up_down + post :delete_answer + post :adjust_score + post :update_scores + end + resource :exercise_answers,only:[:create,:destroy] + end + + + resources :course_modules, shallow: true do + member do + get 'sticky_module' + get 'hidden_module' + post 'rename_module' + post 'add_second_category' + end + collection do + post 'unhidden_modules' + end + end + + resources :course_second_categories, shallow: true do + member do + post 'rename_category' + post 'move_category' + end + collection do + + end + end + + resources :question_banks do + collection do + get :bank_list + post :save_banks + get :my_courses + post :send_to_course + delete :multi_delete + post :multi_public + end + end + + resources :homework_banks do + member do + post :set_public + end + end + + resources :gtopic_banks + resources :task_banks + + resources :exercise_banks do + collection do + get :choose_shixun + end + + member do + get :commit_shixun + end + end + + resources :exercise_bank_questions do + member do + post :up_down + get :choose_shixun + end + end + + resources :poll_bank_questions + + resources :attachments + + resources :schools do + member do + resources :departments, only: [] do + get :for_option, on: :collection + end + end + collection do + get :school_list + get :for_option + end + + scope module: :ecs do + get :detail, to: 'homes#index' + + resources :ec_majors, only: [:index] + resources :ec_major_schools, only: [:index, :create, :destroy] + end + end + resources :add_school_applies, only: [:create] + resources :add_department_applies, only: [:create] + + # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 + scope module: :ecs do + resources :ec_major_schools, only: [] do + resources :major_managers, only: [:create, :destroy] + resources :ec_years, only: [:index, :create, :destroy] + end + + resources :ec_years, only: [] do + resource :ec_training_objectives, only: [:show, :create] + resources :ec_graduation_requirements, only: [:index, :create] + resource :requirement_support_objectives, only: [:show, :create, :destroy] + resource :subitem_support_standards, only: [:show, :create, :destroy] + resource :students, only: [:show, :destroy] do + post :import, on: :collection + end + + resources :ec_courses, only: [:index, :create, :destroy] do + post :link_course, on: :member + + collection do + post :import + get :search + end + end + + resource :graduation_course_supports, only: [:show, :create] + resource :reach_evaluation, only: [:show, :create] + resource :reach_criteria, only: [:create] + end + + resources :ec_courses, only: [] do + resource :evaluation, only: [:show, :create] + resources :course_managers, only: [:create, :destroy] + resources :course_targets, only: [:index, :create] do + get :with_achievement_methods, on: :collection + + resource :course_achievement_methods, only: [:create] + end + resources :course_evaluations, only: [:index, :create, :update, :destroy] do + member do + get :average_score_import_template + get :detail_score_import_template + get :import_student_achievement + end + get :slimmer, on: :collection + end + resource :score_levels, only: [:show, :create] + end + end + + resource :zip, only: [] do + collection do + get :shixun_report + get :export_exercises + end + end + + resources :repertoires, only: [:index] + + scope module: :competitions do + resources :competitions, only: [:index, :show] do + resources :competition_modules, only: [:index, :show, :update] + resource :competition_staff + resources :competition_teams, only: [:index, :show] do + post :join, on: :collection + post :leave, on: :member + end + resources :teachers, only: [:index] + resources :students, only: [:index] + end + end + + resources :project_package_categories, only: [:index] + resources :project_packages, only: [:index, :show, :create, :update, :destroy] do + resources :bidding_users, only: [:create] do + post :win, on: :collection + end + end + + resources :libraries, only: [:index, :show, :create, :update, :destroy] + + scope module: :projects do + resources :project_applies, only: [:create] + end + + post 'callbacks/aliyun_vod', to: 'callbacks/aliyun_vods#create' + end + + namespace :admins do + get '/', to: 'dashboards#index' + resources :dashboards, only: [:index] do + collection do + get :month_active_user + get :evaluate + end + end + resources :files, only: [:create] + + resources :daily_school_statistics, only: [:index] do + get :export, on: :collection + end + + resources :school_statistics, only: [:index] do + get :contrast, on: :collection + end + + resources :users, only: [:index, :edit, :update, :destroy] do + member do + post :reward_grade + post :lock + post :unlock + post :active + end + end + resource :import_users, only: [:create] + resource :import_course_members, only: [:create] + + resources :library_applies, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :video_applies, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :identity_authentications, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :professional_authentications, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :shixun_authorizations, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :subject_authorizations, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :project_package_applies, only: [:index] do + member do + post :agree + post :refuse + end + end + resources :shixuns, only: [:index,:destroy] + resources :shixun_settings, only: [:index,:update] + resources :mirror_repositories, only: [:index, :new, :create, :edit, :update, :destroy] do + collection do + post :merge + get :for_select + end + + resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy] + end + resources :choose_mirror_repositories, only: [:new, :create] + resources :departments, only: [:index, :create, :edit, :update, :destroy] do + resource :department_member, only: [:create, :update, :destroy] + + post :merge, on: :collection + end + resources :myshixuns, only: [:index] + end + + resources :colleges, only: [] do + member do + get :statistics + get :course_statistics + get :student_shixun + get :shixun_time + get :shixun_report_count + get :teachers + get :shixun_chart_data + get :student_hot_evaluations + end + end + + namespace :wechats do + resource :js_sdk_signature, only: [:create] + end + + #git 认证回调 + match 'gitauth/*url', to: 'gits#auth', via: :all + + get 'oauth/get_code', to: 'oauth#get_code' + get 'oauth/get_token_callback', to: 'oauth#get_token_callback' + + root 'main#index' + + ## react用 + get '*path', to: 'main#index', constraints: ReactConstraint.new +end diff --git a/public/react/src/modules/courses/Index.js b/public/react/src/modules/courses/Index.js index fda68665e..457723376 100644 --- a/public/react/src/modules/courses/Index.js +++ b/public/react/src/modules/courses/Index.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import { SnackbarHOC } from 'educoder'; import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; +import { withRouter } from 'react-router' import Loadable from 'react-loadable'; import Loading from '../../Loading'; import axios from 'axios'; @@ -264,6 +265,12 @@ const GraduationTasksSubmiteditApp=Loadable({ loading: Loading, }) +//排序 +const Ordering=Loadable({ + loader: () => import('../../modules/courses/ordering/Ordering'), + loading: Loading, +}); + class CoursesIndex extends Component{ constructor(props) { super(props) @@ -290,6 +297,13 @@ class CoursesIndex extends Component{ componentDidMount(){ // this.updataleftNav() + this.historyArray = [] + this.props.history.listen( location => { + console.log(location) + this.historyArray.unshift(location.pathname) + this.historyArray.length = 2; + //Do your stuff here + }); } updataleftNav=()=>{ @@ -424,6 +438,7 @@ class CoursesIndex extends Component{ render() { const common = { + previousPathName: this.historyArray && this.historyArray[1] // isAdmin: this.isAdmin, // isStudent: this.isStudent, // isAdminOrStudent: this.isAdminOrStudent, @@ -442,27 +457,32 @@ class CoursesIndex extends Component{ // console.log(commons) return ( - + {/*排序*/} + () + } + > {/* 资源列表页 */} () + (props) => () } > () + (props) => () } > () + (props) => () } > {/*课堂讨论*/} () + (props) => () } > @@ -470,19 +490,19 @@ class CoursesIndex extends Component{ {/* 毕设问答 */} () + (props) => () } > {/* 毕设选题新建页 */} () + (props) => () }> {/* 毕设选题编辑页*/} () + (props) => () }> {/* 毕设选题详情页 */} @@ -495,7 +515,7 @@ class CoursesIndex extends Component{ {/* 毕设选题列表 */} () + (props) => () }> @@ -503,21 +523,21 @@ class CoursesIndex extends Component{ {/* 作品评阅 https://www.trustie.net/issues/19981 */} () + (props) => () } > {/* 新建作品 */} () + (props) => () } > {/* 修改作品 */} () + (props) => () } > @@ -525,20 +545,20 @@ class CoursesIndex extends Component{ () + (props) => () } > () + (props) => () }> () + (props) => () } > @@ -547,7 +567,7 @@ class CoursesIndex extends Component{ {/* 修改毕设任务 https://www.trustie.net/issues/19981 */} () + (props) => () } > @@ -555,7 +575,7 @@ class CoursesIndex extends Component{ {/* 新建毕设任务 https://www.trustie.net/issues/19981 */} () + (props) => () } > @@ -563,87 +583,87 @@ class CoursesIndex extends Component{ {/* 毕设任务列表 https://www.trustie.net/issues/19981 */} () + (props) => () } > {/*/!* 毕业设计主 https://www.trustie.net/issues/19981 *!/*/} {/* ()*/} + {/*(props) => ()*/} {/*}*/} {/*>*/} {/*/!* 资源子目录 https://www.trustie.net/issues/19917 *!/*/} {/* ()*/} + {/*(props) => ()*/} {/*}*/} {/*>*/} {/* 教师列表*/} () + (props) => () } > {/* 学生列表*/} () + (props) => () } > {/* 分班列表 */} () + (props) => () } > {/* 普通作业 */} () + (props) => () } > {/* 分组作业 */} () + (props) => () } > {/* 普通作业 */} () + (props) => () } > {/* 分组作业 */} () + (props) => () } > {/* 问卷答题 */} () + (props) => () } > {/* 问卷详情 */} () + (props) => () } > {/* 问卷新建 */} () + (props) => () } > {/*/!* 问卷编辑 *!/*/} @@ -655,7 +675,7 @@ class CoursesIndex extends Component{ {/* 问卷 */} () + (props) => () } > @@ -663,20 +683,20 @@ class CoursesIndex extends Component{ {/* 试卷查看/评阅 */} () + (props)=>() } > {/*试卷新建 */} () + (props) => () } > {/*试卷新建 */} () + (props) => () } > @@ -684,7 +704,7 @@ class CoursesIndex extends Component{ () + (props) => () } > @@ -693,14 +713,14 @@ class CoursesIndex extends Component{ () + (props) => () } > {/* 试卷 */} () + (props) => () } > @@ -708,65 +728,65 @@ class CoursesIndex extends Component{ {/*实训查重详情*/} () + (props) => () } > () + (props) => () } > {/*实训查重列表*/} () + (props) => () } > () + (props) => () } > {/*实训报告*/} () + (props) => () } > () + (props) => () } > {/*教师列表*/} () + (props) => () } > () + (props) => () } > {/*实训作业page*/} () + (props) => () } > {/*实训作业设置*/} () + (props) => () } > () + (props) => () } > {/*/!*实训作品列表教师*!/*/} @@ -805,21 +825,21 @@ class CoursesIndex extends Component{ {/*实训作业问答主目录*/} () + (props) => () } > {/*实训作业问答子目录*/} () + (props) => () } > {/*新建课堂*/} () + (props) => () } > {/*新建精品课堂*/} @@ -827,47 +847,47 @@ class CoursesIndex extends Component{ {/*id 是否是私有或者公有*/} () + (props) => () } > {/*修改精品课堂*/} () + (props) => () } > {/*修改课堂*/} () + (props) => () } > {/* 实训作业子页面*/} () + (props) => () } > {/* 实训作业页面*/} () + (props) => () } > {/*/!*实训作业and课堂详情页*!/*/} () + (props) => () } > {/*课堂首页*/} () + (props) => () } > {/**/} @@ -877,4 +897,4 @@ class CoursesIndex extends Component{ } } -export default ImageLayerOfCommentHOC({imgSelector: '.imageLayerParent img, .imageLayerParent .imageTarget', parentSelector: '.newMain'}) (CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) ))); \ No newline at end of file +export default withRouter(ImageLayerOfCommentHOC({imgSelector: '.imageLayerParent img, .imageLayerParent .imageTarget', parentSelector: '.newMain'}) (CNotificationHOC() ( SnackbarHOC() ( TPMIndexHOC(CoursesIndex) )))); \ No newline at end of file diff --git a/public/react/src/modules/courses/boards/BoardsNew.js b/public/react/src/modules/courses/boards/BoardsNew.js index 58cd0c02b..a08225c1f 100644 --- a/public/react/src/modules/courses/boards/BoardsNew.js +++ b/public/react/src/modules/courses/boards/BoardsNew.js @@ -181,15 +181,16 @@ class BoardsNew extends Component{ } // 附件相关 START handleChange = (info) => { - let fileList = info.fileList; - this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) - }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) }); + } } onAttachmentRemove = (file) => { - if(file.response!=undefined){ - confirm({ + if(!file.percent || file.percent == 100){ + this.props.confirm({ // title: '确定要删除这个附件吗?', - title: '是否确认删除?', + content: '是否确认删除?', okText: '确定', cancelText: '取消', diff --git a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js index d1e271981..698fbd398 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkAppraise.js @@ -218,7 +218,8 @@ class CommonWorkAppraise extends Component{ {item.filesize} {/*{item.delete===true?:""}*/} - {item.delete===true?:""} + {item.delete===true?:""} + {/* style={{display: 'none'}} */} ) })} diff --git a/public/react/src/modules/courses/busyWork/CommonWorkPost.js b/public/react/src/modules/courses/busyWork/CommonWorkPost.js index fec3f02a1..312756ec4 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkPost.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkPost.js @@ -291,7 +291,7 @@ class CommonWorkPost extends Component{ } // 附件相关 START handleChange = (info) => { - if (info.file.status === 'uploading' || info.file.status === 'done') { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList: appendFileSizeToUploadFileAll(fileList) }); @@ -320,11 +320,19 @@ class CommonWorkPost extends Component{ // ModalSave: ()=>this.deleteAttachment(file), // ModalCancel:this.cancelAttachment // }) - if(file.response!=undefined){ - this.deleteAttachment(file) + + if(!file.percent || file.percent == 100){ + this.props.confirm({ + content: '是否确认删除?', + onOk: () => { + this.deleteAttachment(file) + }, + onCancel() { + console.log('Cancel'); + }, + }); return false; } - } cancelAttachment=()=>{ diff --git a/public/react/src/modules/courses/busyWork/NewWork.js b/public/react/src/modules/courses/busyWork/NewWork.js index fb2d18de0..8000de59f 100644 --- a/public/react/src/modules/courses/busyWork/NewWork.js +++ b/public/react/src/modules/courses/busyWork/NewWork.js @@ -3,7 +3,8 @@ import { Input, InputNumber, Form, Button, Checkbox, Upload, Icon, message, Moda import axios from 'axios' import '../css/busyWork.css' import '../css/Courses.css' -import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll } from 'educoder' +import { WordsBtn, getUrl, ConditionToolTip, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll + , getUploadActionUrl } from 'educoder' import TPMMDEditor from '../../tpm/challengesnew/TPMMDEditor'; import CBreadcrumb from '../common/CBreadcrumb' @@ -234,16 +235,20 @@ class NewWork extends Component{ } handleContentUploadChange = (info) => { - let contentFileList = info.fileList; - this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let contentFileList = info.fileList; + this.setState({ contentFileList: appendFileSizeToUploadFileAll(contentFileList) }); + } } handleAnswerUploadChange = (info) => { - let answerFileList = info.fileList; - this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let answerFileList = info.fileList; + this.setState({ answerFileList: appendFileSizeToUploadFileAll(answerFileList) }); + } } onAttachmentRemove = (file, stateName) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.props.confirm({ content: '是否确认删除?', @@ -331,7 +336,7 @@ class NewWork extends Component{ // https://github.com/ant-design/ant-design/issues/15505 // showUploadList={false},然后外部拿到 fileList 数组自行渲染列表。 // showUploadList: false, - action: `${getUrl()}/api/attachments.json`, + action: `${getUploadActionUrl()}`, onChange: this.handleContentUploadChange, onRemove: (file) => this.onAttachmentRemove(file, 'contentFileList'), beforeUpload: (file) => { diff --git a/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js b/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js index 61668207a..833c60e1f 100644 --- a/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js +++ b/public/react/src/modules/courses/completetaskdetails/Completetaskdetails.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -73,7 +73,8 @@ class Groupjobbandetails extends Component { datas.description===""? : -
+ + //
) } {/*
*/} diff --git a/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js b/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js index ba02e05fd..b74ad13e2 100644 --- a/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js +++ b/public/react/src/modules/courses/completetaskdetails/Completetaskpage.js @@ -1,6 +1,6 @@ import React, {Component} from "react"; import {Link, NavLink} from 'react-router-dom'; -import {WordsBtn, ActionBtn} from 'educoder'; +import {WordsBtn, ActionBtn,MarkdownToHtml} from 'educoder'; import axios from 'axios'; import { notification diff --git a/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js b/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js index c314982b6..d62b398c1 100644 --- a/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js +++ b/public/react/src/modules/courses/comtopicdetails/Completetopicdetails.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -72,7 +72,9 @@ class Completetopicdetails extends Component { datas.description===""? : -
+ + + //
) } {/*
*/} diff --git a/public/react/src/modules/courses/coursesPublic/AccessoryModal.js b/public/react/src/modules/courses/coursesPublic/AccessoryModal.js index 3b25ceb6d..750679111 100644 --- a/public/react/src/modules/courses/coursesPublic/AccessoryModal.js +++ b/public/react/src/modules/courses/coursesPublic/AccessoryModal.js @@ -73,7 +73,7 @@ class AccessoryModal extends Component{ // ModalCancel:this.cancelAttachment // }) // return false; - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.deleteAttachment(file); } } diff --git a/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js b/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js index a9a627387..a15cb0617 100644 --- a/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js +++ b/public/react/src/modules/courses/coursesPublic/AccessoryModal2.js @@ -64,7 +64,7 @@ class AccessoryModal2 extends Component{ // ModalCancel:this.cancelAttachment // }) // return false; - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.deleteAttachment(file); } diff --git a/public/react/src/modules/courses/coursesPublic/SelectSetting.js b/public/react/src/modules/courses/coursesPublic/SelectSetting.js index d52b328e2..1a18513e7 100644 --- a/public/react/src/modules/courses/coursesPublic/SelectSetting.js +++ b/public/react/src/modules/courses/coursesPublic/SelectSetting.js @@ -296,7 +296,7 @@ class Selectsetting extends Component{ onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` axios.delete(url, { }) diff --git a/public/react/src/modules/courses/coursesPublic/sendResource.js b/public/react/src/modules/courses/coursesPublic/sendResource.js index 56c85439c..a9ceb6405 100644 --- a/public/react/src/modules/courses/coursesPublic/sendResource.js +++ b/public/react/src/modules/courses/coursesPublic/sendResource.js @@ -132,7 +132,7 @@ class Sendresource extends Component{ onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` axios.delete(url, { }) diff --git a/public/react/src/modules/courses/css/busyWork.css b/public/react/src/modules/courses/css/busyWork.css index 140b431df..92427c753 100644 --- a/public/react/src/modules/courses/css/busyWork.css +++ b/public/react/src/modules/courses/css/busyWork.css @@ -1,80 +1,81 @@ - -.polllisthover:hover { - box-shadow: 0px 2px 6px rgba(51,51,51,0.09); - opacity: 1; - border-radius: 2px; -} - -.workList_Item{ - /* padding:20px 30px; */ - display: flex; - background-color: #fff; - margin-bottom: 20px; - padding-top: 10px; -} -p span{ - cursor: default; -} -.mt-5{ margin-top:-5px;} - - -/* ���ѡ��tab */ -.bankNav li{ - float: left; - margin-right: 20px; -} -.bankNav li:last-child{ - margin-right: 0px; -} -.bankNav li.active a{ - color: #fff!important; - background-color: #4CACFF; -} -.bankNav li a{ - display: block; - padding:0px 10px; - height: 28px; - line-height: 28px; - background-color: #F5F5F5; - border-radius: 36px; - color: #666666!important; -} - - - -.task_menu_ul{ - width: 600px; -} - -.task_menu_ul .ant-menu-item,.task_menu_ul .ant-menu-submenu-title{ - padding:0px; - margin-right: 30px; - line-height: 68px; - font-size: 16px; -} -.ant-menu{ - color: #05101a; -} -.task_menu_ul .ant-menu-horizontal{ - border-bottom: none; -} -.task_menu_ul .ant-menu-horizontal > .ant-menu-item:hover{ - border-bottom:2px solid transparent; -} -.task_menu_ul .ant-menu-horizontal > .ant-menu-item-selected{ - border-bottom: 2px solid #4CACFF !important; -} - -.sourceTag a{ - display: block; - float: left; - background-color:#E5F3FF; - padding: 0px 10px; - height: 24px; - line-height: 24px; - color: #4E7A9B; - margin:5px 0px 5px 10px; -} -.sourceTag a.active{ - color: #FFFFFF;background-color:#4CACFF; -} \ No newline at end of file + +.polllisthover:hover { + box-shadow: 0px 2px 6px rgba(51,51,51,0.09); + opacity: 1; + border-radius: 2px; +} + +.workList_Item{ + /* padding:20px 30px; */ + display: flex; + background-color: #fff; + margin-bottom: 20px; + padding-top: 10px; +} +p span{ + cursor: default; +} +.mt-5{ margin-top:-5px;} + + +/* ���ѡ��tab */ +.bankNav li{ + float: left; + margin-right: 20px; +} +.bankNav li:last-child{ + margin-right: 0px; +} +.bankNav li.active a{ + color: #fff!important; + background-color: #4CACFF; +} +.bankNav li a{ + display: block; + padding:0px 10px; + height: 28px; + line-height: 28px; + background-color: #F5F5F5; + border-radius: 36px; + color: #666666!important; +} + + + +.task_menu_ul{ + width: 600px; +} + +.task_menu_ul .ant-menu-item,.task_menu_ul .ant-menu-submenu-title{ + padding:0px; + margin-right: 30px; + line-height: 68px; + font-size: 16px; +} +.ant-menu{ + color: #05101a; +} +.task_menu_ul .ant-menu-horizontal{ + border-bottom: none; +} +.task_menu_ul .ant-menu-horizontal > .ant-menu-item:hover{ + border-bottom:2px solid transparent; +} +.task_menu_ul .ant-menu-horizontal > .ant-menu-item-selected{ + border-bottom: 2px solid #4CACFF !important; +} + +.sourceTag a{ + display: block; + float: left; + background-color:#E5F3FF; + padding: 0px 10px; + height: 24px; + line-height: 24px; + color: #4E7A9B; + margin:5px 0px 5px 10px; +} +.sourceTag a.active{ + color: #FFFFFF;background-color:#4CACFF; +} + diff --git a/public/react/src/modules/courses/exercise/ExerciseDisplay.js b/public/react/src/modules/courses/exercise/ExerciseDisplay.js index a0296476f..cbaf38c80 100644 --- a/public/react/src/modules/courses/exercise/ExerciseDisplay.js +++ b/public/react/src/modules/courses/exercise/ExerciseDisplay.js @@ -53,11 +53,15 @@ class ExerciseDisplay extends Component{ componentDidMount = () => { const Id = this.props.match.params.Id if (Id) { - const url = `/exercises/${Id}.json` + const url = `/${this.props.urlPath || 'exercises'}/${Id}.json` axios.get(url) .then((response) => { - if (response.data.status == 0) { - this.setState({...response.data}) + if (response.data.exercise) { + response.data.exercise.exercise_description = response.data.exercise.exercise_description || response.data.exercise.description + response.data.exercise.exercise_name = response.data.exercise.exercise_name || response.data.exercise.name + response.data.exercise.exercise_status = response.data.exercise.exercise_status == undefined ? 1 : response.data.exercise.exercise_status + this.setState({...response.data}) + this.props.detailFetchCallback && this.props.detailFetchCallback(response); } }) .catch(function (error) { diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js index b603e375d..3116e8255 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitedit.js @@ -116,7 +116,7 @@ class GraduationTasksSubmitedit extends Component{ this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } - if (info.file.status === 'done') { + if (info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } @@ -157,7 +157,7 @@ class GraduationTasksSubmitedit extends Component{ } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ let {attachments,fileList}=this.state; const url = `/attachments/${file}.json` axios.delete(url, { diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitnew.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitnew.js index ed2731c61..cb7d3c586 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitnew.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksSubmitnew.js @@ -125,7 +125,7 @@ class GraduationTasksSubmitnew extends Component{ this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } - if (info.file.status === 'done') { + if (info.file.status === 'done' || info.file.status === 'removed') { let fileList = info.fileList; this.setState({ fileList:appendFileSizeToUploadFileAll(fileList) }); } @@ -146,7 +146,7 @@ class GraduationTasksSubmitnew extends Component{ // }, // }); // return false; - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.setState({ Modalstype:true, Modalstopval:'确定要删除这个附件吗?', diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseMainEditor.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseMainEditor.js index 6b741f413..6a481c61c 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseMainEditor.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseMainEditor.js @@ -88,7 +88,7 @@ class GraduationTasksappraiseMainEditor extends Component{ this.setState({ fileList }); } onAttachmentRemove = (file, stateName) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.props.confirm({ content: '确定要删除这个附件吗?', okText: '确定', diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksedit.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksedit.js index e6139bad6..256dba7d4 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksedit.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksedit.js @@ -150,7 +150,7 @@ class GraduationTasksedit extends Component{ } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ // debugger this.cancelAttachment(); const url = `/attachments/${file.response ? file.response.id : file.uid}.json` diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksnew.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksnew.js index 3b6b60ac8..da83e8d7e 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksnew.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksnew.js @@ -173,7 +173,7 @@ class GraduationTasksnew extends Component { } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ const url = `/attachments/${file.response ? file.response.id : file.uid}.json` // const url = `/attachments/${file}.json` axios.delete(url, {}) diff --git a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js index 511deb511..28d6fcf77 100644 --- a/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js +++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicNew.js @@ -216,7 +216,7 @@ class GraduateTopicNew extends Component{ } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ confirm({ title: '确定要删除这个附件吗?', okText: '确定', diff --git a/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js b/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js index 3998669d7..60fa071a9 100644 --- a/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js +++ b/public/react/src/modules/courses/graduation/topics/GraduateTopicPostWorksNew.js @@ -163,7 +163,7 @@ class GraduateTopicPostWorksNew extends Component{ this.setState({ fileList }); } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ confirm({ title: '确定要删除这个附件吗?', okText: '确定', diff --git a/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js b/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js index dc6b12a98..a0ba84549 100644 --- a/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js +++ b/public/react/src/modules/courses/groupjobbank/Groupjobbandetails.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -74,7 +74,8 @@ class Groupjobbandetails extends Component { datas.description===""? : -
+ + //
) } {/*
*/} diff --git a/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js b/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js index ae6b227b4..b927f3177 100644 --- a/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js +++ b/public/react/src/modules/courses/groupjobbank/Groupjobquesanswer.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import { WordsBtn,on, off, trigger,markdownToHTML,getImageUrl} from 'educoder'; +import { WordsBtn,on, off, trigger,MarkdownToHtml,getImageUrl} from 'educoder'; import { Button, Checkbox, @@ -71,7 +71,8 @@ class Groupjobquesanswer extends Component { datas.reference_answer===""? : -
+ + //
) } {/*
*/} diff --git a/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js index 77a41e47d..afbe8de58 100644 --- a/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js +++ b/public/react/src/modules/courses/members/modal/CreateGroupByImportModal.js @@ -73,7 +73,7 @@ class CreateGroupByImportModal extends Component{ } onAttachmentRemove = (file) => { - if(file.response!=undefined){ + if(!file.percent || file.percent == 100){ this.props.confirm({ content: '是否确认删除?', diff --git a/public/react/src/modules/courses/ordering/Ordering.css b/public/react/src/modules/courses/ordering/Ordering.css new file mode 100644 index 000000000..a8787de03 --- /dev/null +++ b/public/react/src/modules/courses/ordering/Ordering.css @@ -0,0 +1,109 @@ +.color4CACFF{ + color: #4CACFF !important; +} + +.orderingbox{ + width:1200px; + height:80px; + background:rgba(255,255,255,1); + box-shadow:3px 3px 3px rgba(237,237,237,1); + opacity:1; + border-radius:2px 2px 0px 0px; + padding: 24px; + box-sizing: border-box; + line-height: 34px; +} + +.orderingbtnright{ + width: 90px; + height: 38px; + background: rgba(255,255,255,1); + border: 1px solid rgba(228,228,228,1); + box-shadow: 0px 1px 1px rgba(0,0,0,0.16); + opacity: 1; + border-radius: 4px; +} + +.orderingbtnleft{ + width: 90px; + height: 38px; + background: rgba(76,172,255,1); + box-shadow: 0px 1px 1px rgba(0,0,0,0.16); + opacity: 1; + border-radius: 4px; +} +.pd1323s{ + padding: 10px 6px 25px 40px; + cursor: pointer; +} + + +.orderSection{ + height: 80px; + padding-top: 16px; +} + +.ordermidbox{ + width: 960px; + height: 120px; + background: rgba(255,255,255,1); + /* border: 1px solid rgba(205,205,205,1); */ + opacity: 1; + margin-left:142px; +} + +.orderfonttop{ + font-size: 16px !important; + font-family: Microsoft YaHei; + font-weight: bold; + line-height: 28px; + color: rgba(5,16,26,1); + opacity: 1; +} + +.orderfontbom{ + font-size:14px; + font-family:Microsoft YaHei; + font-weight:400; + line-height:25px; + color:rgba(153,153,153,1); + opacity:1; +} + +.ordermidbox:hover { + box-shadow: 0px 2px 6px rgba(51,51,51,0.09); + opacity: 1; +} + +.mb200{ + margin-bottom: 200px; +} + +.maxwidth865s{ + max-width: 865px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.maxwidth795 { + max-width:795px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + display: inline-block; +} + +.ordermidbox:active{ + background:rgba(248,247,255,1); + border:1px solid rgba(76,172,255,1); +} + +.ordermidbox:focus{ + background:rgba(248,247,255,1); + border:1px solid rgba(76,172,255,1); +} + +.ordermiddiv{ + min-height: 500px; +} diff --git a/public/react/src/modules/courses/ordering/Ordering.js b/public/react/src/modules/courses/ordering/Ordering.js new file mode 100644 index 000000000..68075be72 --- /dev/null +++ b/public/react/src/modules/courses/ordering/Ordering.js @@ -0,0 +1,296 @@ +import React,{ Component } from "react"; +import { Input,Checkbox,Table, Pagination, Modal,Menu, Tooltip,Spin,Breadcrumb,Button } from "antd"; +import { WordsBtn,on, off, trigger } from 'educoder'; +import { DragDropContext,Draggable, Droppable} from 'react-beautiful-dnd'; +import axios from'axios'; +import Modals from '../../modals/Modals'; +import '../css/members.css'; +import '../css/busyWork.css'; +import './Ordering.css'; +import NoneData from "../coursesPublic/NoneData"; + +const reorder = (list, startIndex, endIndex) => { + const result = Array.from(list); + const [removed] = result.splice(startIndex, 1); + result.splice(endIndex, 0, removed); + + return result; +}; + +class Ordering extends Component{ + constructor(props){ + super(props); + this.state={ + isSpin:false, + antIcon:false, + datas:undefined, + windowsscrollTop:false, + newtask_ids:[] + } + } + + componentDidMount() { + this.setState({ + isSpin:true + }) + + let coursesId=this.props.match.params.coursesId; + let ordering_type=this.props.match.params.ordering_type; + let url=`/courses/${coursesId}/tasks_list.json`; + axios.get((url),{params:{ + container_type:ordering_type + }}).then((result)=>{ + if(result){ + this.setState({ + datas:result.data.tasks, + isSpin:false + }) + } + }).catch((error)=>{ + console.log(error); + this.setState({ + isSpin:false + }) + }) + + window.addEventListener('scroll', this.handleScroll.bind(this)) //监听滚动 + // window.addEventListener('resize', this.handleResize.bind(this)) //监听窗口大小改变 + } + + + // componentWillUnmount() { //一定要最后移除监听器,以防多个组件之间导致this的指向紊乱 + // window.removeEventListener('scroll', this.handleScroll.bind(this)) + // window.removeEventListener('resize', this.handleResize.bind(this)) + // } + + handleScroll=(e)=>{ + // console.log( + // '浏览器滚动事件', + // e.srcElement.scrollingElement.scrollTop, + // e.srcElement.scrollingElement.scrollHeight + // ) + //e.srcElement.scrollingElement.scrollTop为距离滚动条顶部高度 + // e.srcElement.scrollingElement.scrollHeight为整个文档高度 + + if(e.srcElement.scrollingElement.scrollTop>60){ + this.setState({ + windowsscrollTop:true, + }) + } + + if(e.srcElement.scrollingElement.scrollTop===0){ + this.setState({ + windowsscrollTop:false + }) + } + } + // + // handleResize = e => { + // console.log('浏览器窗口大小改变事件', e.target.innerWidth) + // } + + + + onDragEnd=(result)=>{ + + if(result.destination!=null&&result.destination!=undefined){ + let {datas}=this.state; + if (!result.destination) { + console.log('dropped outside the list') + return; + } + if (result.destination.index === result.source.index) { + console.log('the same') + return; + } + const shixuns_list = reorder( + datas, + result.source.index, + result.destination.index + ); + + let newtask_ids=[] + shixuns_list.map((item,key)=>{ + newtask_ids.push(item.task_id) + }) + + this.setState({ + datas:shixuns_list, + newtask_ids:newtask_ids + }) + } + + } + + updatalist=()=>{ + + let {datas,newtask_ids,isSpin}=this.state; + if(newtask_ids.length===0){ + this.props.showNotification("请先移动需要排序的实训作业任务"); + return + } + + if(isSpin===true){ + return + } + + this.setState({ + isSpin:true + }) + let coursesId=this.props.match.params.coursesId; + let ordering_type=this.props.match.params.ordering_type; + let url=`/courses/${coursesId}/update_task_position.json`; + axios.post(url,{ + container_type:ordering_type, + task_ids:newtask_ids + }).then((result)=>{ + if(result.data.status===0){ + this.props.showNotification(result.data.message); + this.setState({ + isSpin:false, + datas:datas, + newtask_ids:[] + }); + }else{ + this.setState({ + isSpin:false, + }); + } + + }).catch((error)=>{ + this.setState({ + isSpin:false, + }); + }) + + } + + goback=()=>{ + window.location.href=`/courses/${this.props.match.params.coursesId}/shixun_homeworks/${this.props.match.params.main_id}` + } + + + render(){ + let { + datas, + Modalstype, + windowsscrollTop, + }=this.state; + + let main_id=this.props.match.params.main_id; + let category_id=this.props.match.params.category_id; + + console.log(this.props) + console.log(window) + + let positiontype=null; + + if(windowsscrollTop===true){ + positiontype={position:'fixed',zIndex:'9000',left:'20%',top: '0px'} + }else{ + positiontype={} + } + return( + +
+ {/*提示*/} + {Modalstype&&Modalstype===true?:""} + + +
+ + {windowsscrollTop===false?
+ + + {this.props.current_user&&this.props.current_user.course_name} + 实训作业 + 调整排序 + + +
:""} + + +

+ 温馨提示:请在列表中长按鼠标左键,进行拖放排序。完成排序后请点击“保存” + + +

+ + +
+ + + + + {(provided, snapshot) => ( +
+ {datas===undefined?"": + datas.map((item, index) => { + return ( + + {(provided, snapshot) => ( +
+
+
+
+

{item.task_name}

+

+ + {item.user_name} + {item.category} + +

+
+
+
+
+ )} +
+ ) + }) + + } +
+ )} +
+
+ + + + { + datas===undefined?"":datas.length===0? :"" + } + +
+ +
+ ) + } +} +export default Ordering; diff --git a/public/react/src/modules/courses/poll/PollNewQuestbank.js b/public/react/src/modules/courses/poll/PollNewQuestbank.js index 331478cab..a93d5e40c 100644 --- a/public/react/src/modules/courses/poll/PollNewQuestbank.js +++ b/public/react/src/modules/courses/poll/PollNewQuestbank.js @@ -1014,6 +1014,7 @@ class PollNewQuestbank extends Component { return; } + if(object.question.max_choices){ if(object.question.max_choices>0){ if(object.question.min_choices){ @@ -1244,6 +1245,7 @@ class PollNewQuestbank extends Component { return; } + if(object.question.max_choices){ if(object.question.max_choices>0){ if(object.question.min_choices){ @@ -1563,6 +1565,8 @@ class PollNewQuestbank extends Component { return; } + + if(object.question.max_choices){ if(object.question.max_choices>0){ if(object.question.min_choices){ @@ -1594,6 +1598,7 @@ class PollNewQuestbank extends Component { } } + var questiontwo = {}; var other = []; var option = []; @@ -1764,6 +1769,8 @@ class PollNewQuestbank extends Component { return; } + + if(object.question.max_choices){ if(object.question.max_choices>0){ if(object.question.min_choices){ @@ -1958,8 +1965,8 @@ class PollNewQuestbank extends Component { question_title: object.question.question_title, question_type: number, is_necessary: object.question.is_necessary, - max_choices: max_choicess===undefined?length:max_choicess===null?length:max_choicess===0?length:max_choicess, - min_choices: min_choicess===undefined?2:min_choicess===null?2:min_choicess===0?2:min_choicess, + max_choices: max_choicess===undefined||max_choicess===null||max_choicess===0||max_choicess==="0"?null:max_choicess, + min_choices: min_choicess===undefined||min_choicess===null||min_choicess===0||min_choicess==="0"?null:min_choicess, question_answers: option, question_other_answer: null, insert_id: insert_id @@ -2030,8 +2037,8 @@ class PollNewQuestbank extends Component { question_title: object.question.question_title, question_type: number, is_necessary: object.question.is_necessary, - max_choices: max_choicess===undefined?length:max_choicess===null?length:max_choicess===0?length:max_choicess, - min_choices: min_choicess===undefined?2:min_choicess===null?2:min_choicess===0?2:min_choicess, + max_choices: max_choicess===undefined||max_choicess===null||max_choicess===0||max_choicess==="0"?null:max_choicess, + min_choices: min_choicess===undefined||min_choicess===null||min_choicess===0||min_choicess==="0"?null:min_choicess, question_answers: option, question_other_answer: null, }; @@ -2401,11 +2408,10 @@ class PollNewQuestbank extends Component { }) // } - } //最大值 - HandleGradationGroupChangeee = (value, index, minchoices, length) => { + HandleGradationGroupChangeee = (value, index,minchoices,length) => { // console.log("2112"); // console.log(value); // console.log(minchoices); @@ -2439,6 +2445,7 @@ class PollNewQuestbank extends Component { this.setState({ adddom: arr }) + // console.log(this.state.adddom); } //提交题目//没有就创建新的题库,新建问newz题和保存题目不一样不能同时保存 这里只是新建 和编辑 标题和须知 @@ -2968,13 +2975,8 @@ class PollNewQuestbank extends Component { className="color-grey-9 fl">{item.question.question_type === 1 ? "单选题" : item.question.question_type === 2 ? "多选题" : "主观题"} {item.question.is_necessary === 1 ? "(必答)" : item.question.question_type === 2 ? "(选答)" : "(选答)"} - { - item.question.question_type === 2? - {(item.question.min_choices === undefined && item.question.max_choices === undefined ? "不限制" : item.question.min_choices === null && item.question.max_choices === null ? "不限制" : item.question.min_choices === 0 && item.question.max_choices === 0 ? "": item.question.min_choices === "null" && item.question.max_choices === "null" ? "不限制" : item.question.min_choices === item.question.max_choices && item.question.max_choices === item.question.min_choices ? "可选"+(item.question.max_choices)+"项" : "可选" +(item.question.min_choices===undefined||item.question.min_choices===null||item.question.min_choices===""||item.question.min_choices==="null"?2:item.question.min_choices) + "-" + (item.question.max_choices===undefined||item.question.max_choices===null||item.question.max_choices===""||item.question.max_choices==="null"?item.question.answers.length:item.question.max_choices) + "项")} - : "" - } - + {(item.question.min_choices === undefined && item.question.max_choices === undefined ? "不限制" : item.question.min_choices === null && item.question.max_choices === null ? "不限制" : item.question.min_choices === 0 && item.question.max_choices === 0 ? "": item.question.min_choices === "null" && item.question.max_choices === "null" ? "不限制" : item.question.min_choices === item.question.max_choices && item.question.max_choices === item.question.min_choices ? "可选"+(item.question.max_choices)+"项" : "可选" +(item.question.min_choices===undefined||item.question.min_choices===null||item.question.min_choices===""||item.question.min_choices==="null"?2:item.question.min_choices) + "-" + (item.question.max_choices===undefined||item.question.max_choices===null||item.question.max_choices===""||item.question.max_choices==="null"?item.question.answers.length:item.question.max_choices) + "项")} { polls_status === undefined || polls_status === 1 ? @@ -3168,12 +3170,12 @@ class PollNewQuestbank extends Component { { itemo.question.answers[itemo.question.answers.length - 1].answer_text === "其他" && itemo.question.answers.length - 2 === indext ? - this.Ewoption(itemo.question.id, itemo)}> : itemo.question.answers.length - 1 === indext ? - this.Ewoption(itemo.question.id, itemo)}> @@ -3182,7 +3184,7 @@ class PollNewQuestbank extends Component { } : indext === 1 && itemo.question.answers.length === 2 || indext === 1 && itemo.question.answers.length === 3 ? - this.Ewoption(itemo.question.id, itemo)}> : "" @@ -3231,7 +3233,7 @@ class PollNewQuestbank extends Component { 可选
- {/*可选最小*/} + {/*可选最小1*/}