diff --git a/Gemfile.lock b/Gemfile.lock index 6a4a7e08f..8aa2daa6a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -378,6 +378,7 @@ DEPENDENCIES kaminari (~> 1.1, >= 1.1.1) listen (>= 3.0.5, < 3.2) mysql2 (>= 0.4.4, < 0.6.0) + newrelic_rpm oauth2 pdfkit puma (~> 3.11) diff --git a/app/assets/javascripts/admins/schools/index.js b/app/assets/javascripts/admins/schools/index.js new file mode 100644 index 000000000..20ea080fb --- /dev/null +++ b/app/assets/javascripts/admins/schools/index.js @@ -0,0 +1,4 @@ +$(document).on('turbolinks:load', function() { + if ($('body.admins-schools-index-page').length > 0) { + } +}); \ No newline at end of file diff --git a/app/assets/stylesheets/admins/schools.scss b/app/assets/stylesheets/admins/schools.scss new file mode 100644 index 000000000..8dff1eaff --- /dev/null +++ b/app/assets/stylesheets/admins/schools.scss @@ -0,0 +1,3 @@ +.admins-schools-index-page { + +} \ No newline at end of file diff --git a/app/controllers/admins/schools_controller.rb b/app/controllers/admins/schools_controller.rb new file mode 100644 index 000000000..8c4f1d59e --- /dev/null +++ b/app/controllers/admins/schools_controller.rb @@ -0,0 +1,30 @@ +class Admins::SchoolsController < Admins::BaseController + def index + params[:sort_by] ||= 'created_at' + params[:sort_direction] ||= 'desc' + + schools = Admins::SchoolQuery.call(params) + + @schools = paginate schools + + school_ids = @schools.map(&:id) + @department_count = Department.where(school_id: school_ids).group(:school_id).count + end + + def destroy + users = User.joins(:user_extension).where(user_extensions: { school_id: current_school.id }) + + ActiveRecord::Base.transaction do + users.update_all(profile_completed: false) + current_school.destroy! + end + + render_delete_success + end + + private + + def current_school + @_current_school ||= School.find(params[:id]) + end +end \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 2ce52d405..508d005a4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,6 +14,7 @@ class ApplicationController < ActionController::Base #before_action :check_account DCODES = %W(2 3 4 5 6 7 8 9 a b c f e f g h i j k l m n o p q r s t u v w x y z) + OPENKEY = "79e33abd4b6588941ab7622aed1e67e8" helper_method :current_user @@ -246,6 +247,17 @@ class ApplicationController < ActionController::Base User.current = find_current_user uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) + # 开放课程通过链接访问的用户 + if !User.current.logged? && !params[:chinaoocTimestamp].blank? && !params[:websiteName].blank? && !params[:chinaoocKey].blank? + content = "#{OPENKEY}#{params[:websiteName]}#{params[:chinaoocTimestamp]}" + + if Digest::MD5.hexdigest(content) == params[:chinaoocKey] + user = open_class_user + start_user_session(user) if user + User.current = user + end + end + if !User.current.logged? && Rails.env.development? User.current = User.find 1 end @@ -604,4 +616,27 @@ class ApplicationController < ActionController::Base def set_export_cookies cookies[:fileDownload] = true end + + # 149课程的评审用户数据创建(包含创建课堂学生) + def open_class_user + user = User.find_by(login: "OpenClassUser") + unless user + ActiveRecord::Base.transaction do + user_params = {status: 1, login: "OpenClassUser", lastname: "开放课程", + nickname: "开放课程", professional_certification: 1, certification: 1, grade: 0, + password: "12345678", phone: "11122223333", profile_completed: 1} + user = User.create!(user_params) + + UserExtension.create!(user_id: user.id, gender: 0, school_id: 3396, :identity => 1, :student_id => "openclassuser") # 3396 + + subject = Subject.find_by(id: 149) + if subject + subject.courses.each do |course| + CourseMember.create!(course_id: course.id, role: 3, user_id: user.id) if !course.course_members.exists?(user_id: user.id) + end + end + end + end + user + end end diff --git a/app/controllers/colleges_controller.rb b/app/controllers/colleges_controller.rb index 66d327649..f869e9ec6 100644 --- a/app/controllers/colleges_controller.rb +++ b/app/controllers/colleges_controller.rb @@ -40,8 +40,8 @@ class CollegesController < ApplicationController def teachers @teachers = User.find_by_sql("SELECT users.id, users.login, users.lastname, users.firstname, users.nickname, IFNULL((SELECT count(shixuns.id) FROM shixuns where shixuns.user_id =users.id group by shixuns.user_id), 0) AS publish_shixun_count, - (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND m.user_id=users.id AND c.is_delete = 0) as course_count - FROM `users`, user_extensions ue where users.id=ue.user_id and ue.identity=0 and ue.school_id=#{current_school.id} ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") + (SELECT count(c.id) FROM courses c, course_members m WHERE c.id != 1309 and m.course_id = c.id AND m.user_id=users.id AND m.role in (1,2,3) and c.school_id = #{current_school.id} AND c.is_delete = 0) as course_count + FROM `users`, user_extensions ue where ue.school_id=#{current_school.id} and users.id=ue.user_id and ue.identity=0 ORDER BY publish_shixun_count desc, course_count desc, id desc LIMIT 10") # ).order("publish_shixun_count desc, experience desc").limit(10) @teachers = @teachers.map do |teacher| diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index c19c6fdd6..9242b87ac 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -23,7 +23,7 @@ module GitHelper Rails.logger.info "encoding: #{cd['encoding']} confidence: #{cd['confidence']}" # 字符编码问题,GB18030编码识别率不行 decode_content = - if cd["encoding"] == 'GB18030' && cd['confidence'] == 1.0 + if cd["encoding"] == 'GB18030' && cd['confidence'] > 0.8 content.encode('UTF-8', 'GBK', {:invalid => :replace, :undef => :replace, :replace => ' '}) else content.force_encoding('UTF-8') diff --git a/app/controllers/concerns/paginate_helper.rb b/app/controllers/concerns/paginate_helper.rb index bbe84a348..7233adebf 100644 --- a/app/controllers/concerns/paginate_helper.rb +++ b/app/controllers/concerns/paginate_helper.rb @@ -3,6 +3,10 @@ module PaginateHelper page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : opts[:per_page] || 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file diff --git a/app/controllers/ecs/base_controller.rb b/app/controllers/ecs/base_controller.rb index 2cded249a..1ad40d7b3 100644 --- a/app/controllers/ecs/base_controller.rb +++ b/app/controllers/ecs/base_controller.rb @@ -47,6 +47,10 @@ class Ecs::BaseController < ApplicationController page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file diff --git a/app/controllers/ecs/ec_graduation_requirements_controller.rb b/app/controllers/ecs/ec_graduation_requirements_controller.rb index 95dafdb3c..0647a7914 100644 --- a/app/controllers/ecs/ec_graduation_requirements_controller.rb +++ b/app/controllers/ecs/ec_graduation_requirements_controller.rb @@ -15,19 +15,31 @@ class Ecs::EcGraduationRequirementsController < Ecs::BaseController end def create - graduation_requirement = current_year.graduation_requirements.new + graduation_requirement = current_year.ec_graduation_requirements.new @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params) render 'show' end def update - graduation_requirement = current_year.graduation_requirements.find(params[:id]) - @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, update_params) + @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(current_graduation_requirement, update_params) render 'show' end + def destroy + ActiveRecord::Base.transaction do + current_graduation_requirement.destroy! + current_year.ec_graduation_requirements.where('position > ?', current_graduation_requirement.position) + .update_all('position = position - 1') + end + render_ok + end + private + def current_graduation_requirement + @_current_graduation_requirement ||= current_year.ec_graduation_requirements.find(params[:id]) + end + def create_params params.permit(:position, :content, graduation_subitems: [:content]) end diff --git a/app/controllers/ecs/ec_major_schools_controller.rb b/app/controllers/ecs/ec_major_schools_controller.rb index 058bc888e..c5f187af0 100644 --- a/app/controllers/ecs/ec_major_schools_controller.rb +++ b/app/controllers/ecs/ec_major_schools_controller.rb @@ -1,4 +1,6 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController + skip_before_action :check_user_permission!, only: [:show] + def index major_schools = current_school.ec_major_schools.not_template @@ -20,7 +22,18 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController @count = major_schools.count #检索后的数量,小于或等于全部数量 @major_schools = paginate(major_schools.includes(:users, :ec_major)) - @template_major_school = current_school.ec_major_schools.is_template.first #示例专业 + @template_major_school = EcMajorSchool.is_template.first #示例专业 + end + + # :show是 /api/ec_major_schools/:id + def show + @major = EcMajorSchool.find(params[:id]) + school = @major.school + + return if current_user.admin? || school.manager?(current_user) + return if @major.manager?(current_user) + + render_forbidden end def create diff --git a/app/controllers/ecs/ec_majors_controller.rb b/app/controllers/ecs/ec_majors_controller.rb index 7b14237dc..e8daaf008 100644 --- a/app/controllers/ecs/ec_majors_controller.rb +++ b/app/controllers/ecs/ec_majors_controller.rb @@ -1,7 +1,7 @@ class Ecs::EcMajorsController < Ecs::BaseController def index - school_major_subquery = current_school.ec_major_schools.select(:ec_major_id) #学校已选择的专业 - ec_majors = EcMajor.where.not(id: school_major_subquery) + @major_ids = current_school.ec_major_schools.pluck(:ec_major_id) #学校已选择的专业 + ec_majors = EcMajor.all if params[:search].present? ec_majors = ec_majors.search_name_or_code(params[:search]) diff --git a/app/controllers/ecs/ec_training_objectives_controller.rb b/app/controllers/ecs/ec_training_objectives_controller.rb index 318faa6ff..79b232822 100644 --- a/app/controllers/ecs/ec_training_objectives_controller.rb +++ b/app/controllers/ecs/ec_training_objectives_controller.rb @@ -2,7 +2,7 @@ class Ecs::EcTrainingObjectivesController < Ecs::BaseController before_action :check_major_manager_permission!, only: [:create] def show - @training_objective = current_year.ec_training_objective + @training_objective = current_year.ec_training_objective || current_year.build_ec_training_objective respond_to do |format| format.json diff --git a/app/controllers/ecs/ec_years_controller.rb b/app/controllers/ecs/ec_years_controller.rb index 2257911a7..9764e451d 100644 --- a/app/controllers/ecs/ec_years_controller.rb +++ b/app/controllers/ecs/ec_years_controller.rb @@ -10,7 +10,7 @@ class Ecs::EcYearsController < Ecs::BaseController end @count = ec_years.count - @ec_years = paginate ec_years + @ec_years = paginate ec_years.order(year: :desc) return if @ec_years.blank? @@ -27,13 +27,17 @@ class Ecs::EcYearsController < Ecs::BaseController .where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count end + def show + @year = current_year + end + def create if current_major_school.ec_years.exists?(year: params[:year].to_i) render_error('届别已存在') return end - @ec_year = CopyEcYearService.call(current_major_school, params[:year].to_i) + @ec_year = Ecs::CopyEcYearService.call(current_major_school, params[:year].to_i) end def destroy diff --git a/app/controllers/ecs/graduation_course_supports_controller.rb b/app/controllers/ecs/graduation_course_supports_controller.rb index 2a6d59024..c70121a0d 100644 --- a/app/controllers/ecs/graduation_course_supports_controller.rb +++ b/app/controllers/ecs/graduation_course_supports_controller.rb @@ -3,6 +3,7 @@ class Ecs::GraduationCourseSupportsController < Ecs::BaseController def show @graduation_subitems = current_year.ec_graduation_subitems + .reorder('ec_graduation_requirements.position ASC, ec_graduation_subitems.position ASC') .includes(:ec_graduation_requirement, ec_course_supports: :ec_course) @course_count = current_year.ec_courses.count diff --git a/app/controllers/ecs/graduation_subitems_controller.rb b/app/controllers/ecs/graduation_subitems_controller.rb new file mode 100644 index 000000000..03cf379bb --- /dev/null +++ b/app/controllers/ecs/graduation_subitems_controller.rb @@ -0,0 +1,6 @@ +class Ecs::GraduationSubitemsController < Ecs::BaseController + def index + subitems = current_year.ec_graduation_subitems.reorder('ec_graduation_requirements.position ASC, ec_graduation_subitems.position ASC') + @graduation_subitems = subitems.includes(:ec_graduation_requirement) + end +end \ No newline at end of file diff --git a/app/controllers/ecs/major_managers_controller.rb b/app/controllers/ecs/major_managers_controller.rb index da5682734..d2515745b 100644 --- a/app/controllers/ecs/major_managers_controller.rb +++ b/app/controllers/ecs/major_managers_controller.rb @@ -3,7 +3,8 @@ class Ecs::MajorManagersController < Ecs::BaseController before_action :check_manager_permission! def create - @user = Ecs::CreateMajorManagerService.call(current_major_school, params[:user_id]) + Ecs::CreateMajorManagerService.call(current_major_school, params[:user_ids]) + render_ok rescue Ecs::CreateMajorManagerService::Error => ex render_error(ex.message) end diff --git a/app/controllers/ecs/reach_evaluations_controller.rb b/app/controllers/ecs/reach_evaluations_controller.rb index 97576447c..25ac24656 100644 --- a/app/controllers/ecs/reach_evaluations_controller.rb +++ b/app/controllers/ecs/reach_evaluations_controller.rb @@ -14,5 +14,13 @@ class Ecs::ReachEvaluationsController < Ecs::BaseController end def create + relations = current_year.ec_graduation_requirements.joins(ec_graduation_subitems: :ec_course_support) + ec_course_ids = relations.pluck('ec_course_supports.ec_course_id').uniq + + EcCourse.where(id: ec_course_ids).each do |ec_course| + Ecs::CalculateCourseEvaluationService.call(ec_course) + end + + render_ok end end diff --git a/app/controllers/ecs/students_controller.rb b/app/controllers/ecs/students_controller.rb index c21d625e0..abc5ddb65 100644 --- a/app/controllers/ecs/students_controller.rb +++ b/app/controllers/ecs/students_controller.rb @@ -14,7 +14,7 @@ class Ecs::StudentsController < Ecs::BaseController end def import - success_count = Ecs::ImportStudentService.call(current_year, params[:attachment_id]) + success_count = Ecs::ImportStudentService.call(current_year, params) render_ok(success_count: success_count) rescue Ecs::ImportStudentService::Error => ex render_error(ex.message) diff --git a/app/controllers/ecs/users_controller.rb b/app/controllers/ecs/users_controller.rb new file mode 100644 index 000000000..139893efc --- /dev/null +++ b/app/controllers/ecs/users_controller.rb @@ -0,0 +1,22 @@ +class Ecs::UsersController < Ecs::BaseController + skip_before_action :check_user_permission! + before_action :check_manager_permission! + + def index + users = UserQuery.call(params) + + @count = users.count + @users = paginate users.includes(user_extension: [:school, :department]) + @manager_ids = current_major_school.ec_major_school_users.pluck(:user_id) + end + + private + + def current_major_school + @_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id]) + end + + def current_school + @_current_school ||= current_major_school.school + end +end diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb index a159cff59..841b516bb 100644 --- a/app/controllers/graduation_tasks_controller.rb +++ b/app/controllers/graduation_tasks_controller.rb @@ -324,7 +324,7 @@ class GraduationTasksController < ApplicationController tip_exception("缺少截止时间参数") if params[:end_time].blank? tip_exception("截止时间必须晚于当前时间") if params[:end_time] <= strf_time(Time.now) tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) # ActiveRecord::Base.transaction do begin @@ -401,7 +401,7 @@ class GraduationTasksController < ApplicationController tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") tip_exception("截止时间不能早于发布时间") if params[:publish_time] > params[:end_time] tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.publish_time = params[:publish_time] @task.end_time = params[:end_time] @@ -414,7 +414,7 @@ class GraduationTasksController < ApplicationController tip_exception("截止时间不能为空") if params[:end_time].blank? tip_exception("截止时间不能早于当前时间") if params[:end_time] <= Time.now.strftime("%Y-%m-%d %H:%M:%S") tip_exception("截止时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:end_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:end_time] > strf_time(@course.end_date.end_of_day) @task.end_time = params[:end_time] end @@ -426,7 +426,7 @@ class GraduationTasksController < ApplicationController tip_exception("补交结束时间不能为空") if params[:late_time].blank? tip_exception("补交结束时间不能早于截止时间") if params[:late_time] <= @task.end_time tip_exception("补交结束时间不能晚于课堂结束时间(#{@course.end_date.end_of_day.strftime("%Y-%m-%d %H:%M")})") if - @course.end_date.present? && params[:late_time] > @course.end_date.end_of_day + @course.end_date.present? && params[:late_time] > strf_time(@course.end_date.end_of_day) tip_exception("迟交扣分应为正整数") if params[:late_penalty] && params[:late_penalty].to_i < 0 @task.allow_late = true diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index fc5db713f..bf067b389 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -271,7 +271,11 @@ class MyshixunsController < ApplicationController unless @hide_code || @myshixun.shixun&.vnc_evaluate # 远程版本库文件内容 last_content = GitService.file_content(repo_path: @repo_path, path: path)["content"] - content = params[:content] + content = if @myshixun.mirror_name.select {|a| a.include?("MachineLearning") || a.include?("Python")}.present? && params[:content].present? + params[:content].gsub(/\t/, ' ').gsub(/ /, ' ') # 这个不是空格,在windows机器上带来的问题 + else + params[:content] + end Rails.logger.info("###11222333####{content}") Rails.logger.info("###222333####{last_content}") diff --git a/app/controllers/question_banks_controller.rb b/app/controllers/question_banks_controller.rb index b4e98e05f..60b9a807c 100644 --- a/app/controllers/question_banks_controller.rb +++ b/app/controllers/question_banks_controller.rb @@ -264,8 +264,9 @@ class QuestionBanksController < ApplicationController # new_exercise.create_exercise_list # exercise.update_column(:quotes, exercise.quotes+1) # end - new_exercise if new_exercise.save! + new_exercise.save! exercise.update_column(:quotes, exercise.quotes+1) + new_exercise end end @@ -292,8 +293,9 @@ class QuestionBanksController < ApplicationController # new_poll.create_polls_list # poll.update_column(:quotes, poll.quotes+1) # end - new_poll if new_poll.save! + new_poll.save! poll.update_column(:quotes, poll.quotes+1) + new_poll end end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index ab62cbd45..2612510c5 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -321,11 +321,12 @@ class StudentWorksController < ApplicationController ActiveRecord::Base.transaction do begin - revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last - if revise_attachment.present? && @work.student_works_scores.where("created_at > '#{revise_attachment.created_on}' - and score is not null").count == 0 - revise_attachment.destroy - end + # 补交作业附件不覆盖之前上传的附件 + # revise_attachment = @work.attachments.where(attachtype: 7).reorder("created_on desc").last + # if revise_attachment.present? && @work.student_works_scores.where("created_at > '#{revise_attachment.created_on}' + # and score is not null").count == 0 + # revise_attachment.destroy + # end Attachment.associate_container(params[:attachment_ids], @work.id, @work.class, 7) revise_attachment = Attachment.where(attachtype: 7, container_id: @work.id, container_type: "StudentWork").last revise_attachment.update_attributes(description: params[:description]) if revise_attachment.present? diff --git a/app/controllers/subjects_controller.rb b/app/controllers/subjects_controller.rb index 36f14a5d5..ba9b13f85 100644 --- a/app/controllers/subjects_controller.rb +++ b/app/controllers/subjects_controller.rb @@ -368,7 +368,7 @@ class SubjectsController < ApplicationController @schools.map do |s| school_courses = Course.where(id: course_ids, school_id: s.id) course_count = school_courses.count - student_count = StudentsForCourse.where(course_id: school_courses.pluck(:id)).count + student_count = CourseMember.where(course_id: school_courses.pluck(:id), role: 4).count homework_count = HomeworkCommon.find_by_sql("select count(*) cnt from homework_commons hc join courses c on hc.course_id = c.id where c.school_id = #{s.id} and hc.id in(#{homework_common_id})").first.try(:cnt) s.attributes.dup.merge({name: s.name, course_count: course_count, student_count: student_count,homework_count: homework_count}) diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb index 3ba6940f5..128dc539b 100644 --- a/app/controllers/users/base_controller.rb +++ b/app/controllers/users/base_controller.rb @@ -55,7 +55,13 @@ class Users::BaseController < ApplicationController page = page_value per_page = per_page_value - return Kaminari.paginate_array(objs).page(page).per(per_page) unless opts[:special] && observed_logged_user? + unless opts[:special] && observed_logged_user? + if objs.is_a?(Array) + return Kaminari.paginate_array(objs).page(page).per(per_page) + else + return objs.page(page).per(per_page) + end + end # note: 为实现第一页少一条记录,让前端放置新建入口 if page == 1 diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index df642a074..851c3d075 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -81,7 +81,7 @@ module TidingDecorator end def student_join_course_content - I18n.t(locale_format) % Course.find_by(id: container_id)&.name + I18n.t(locale_format) % [trigger_user.show_real_name, Course.find_by(id: container_id)&.name] end def teacher_join_course_content diff --git a/app/helpers/ecs/ec_years_helper.rb b/app/helpers/ecs/ec_years_helper.rb new file mode 100644 index 000000000..108abb0e7 --- /dev/null +++ b/app/helpers/ecs/ec_years_helper.rb @@ -0,0 +1,22 @@ +module Ecs::EcYearsHelper + def achieved_graduation_course_count(ec_year) + return 0 if ec_year.ec_courses.count.zero? + + course_ids = ec_year.ec_courses.map(&:id) + target_count_map = EcCourseTarget.where(ec_course_id: course_ids).group(:ec_course_id).count + + ec_year.ec_courses.sum { |course| course.complete_target_count == target_count_map[course.id] ? 1 : 0 } + end + + def achieved_graduation_objective_count(ec_year) + return 0 if ec_year.ec_graduation_subitems.count.zero? + + subitem_ids = ec_year.ec_graduation_subitems.reorder(nil).pluck(:id) + + relations = EcGraduationRequirementCalculation.joins(:ec_course_support).where(ec_course_supports: { ec_graduation_subitem_id: subitem_ids }) + + reached_map = relations.where(status: true).group('ec_graduation_subitem_id').count + + reached_map.keys.size + end +end \ No newline at end of file diff --git a/app/jobs/apply_teacher_role_join_course_notify_job.rb b/app/jobs/apply_teacher_role_join_course_notify_job.rb index 3ae5e32db..ab5a9e354 100644 --- a/app/jobs/apply_teacher_role_join_course_notify_job.rb +++ b/app/jobs/apply_teacher_role_join_course_notify_job.rb @@ -8,7 +8,7 @@ class ApplyTeacherRoleJoinCourseNotifyJob < ApplicationJob return if user.blank? || course.blank? attrs = %i[user_id trigger_user_id container_id container_type belong_container_id - belong_container_type tiding_type extra created_at updated_at] + belong_container_type tiding_type status extra created_at updated_at] same_attrs = { trigger_user_id: user.id, container_id: course.id, container_type: 'JoinCourse', status: 0, diff --git a/app/libs/util.rb b/app/libs/util.rb index f39ce2b58..ae2e4b80b 100644 --- a/app/libs/util.rb +++ b/app/libs/util.rb @@ -45,6 +45,8 @@ module Util def conceal(str, type = nil) str = str.to_s + return if str.blank? + case type when :phone then "#{str[0..2]}***#{str[-4..-1]}" when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}" diff --git a/app/libs/util/file_manage.rb b/app/libs/util/file_manage.rb index f592ca4e7..b6cd79e57 100644 --- a/app/libs/util/file_manage.rb +++ b/app/libs/util/file_manage.rb @@ -18,10 +18,18 @@ module Util::FileManage File.exist?(disk_filename(source_type, source_id)) end + def exists?(source) + File.exist?(disk_filename(source.class, source.id)) + end + def disk_file_url(source_type, source_id) File.join('/images', relative_path, "#{source_type}", "#{source_id}") end + def source_disk_file_url(source) + File.join('/images', relative_path, "#{source.class}", "#{source.id}") + end + def disk_auth_filename(source_type, source_id, type) File.join(storage_path, "#{source_type}", "#{source_id}#{type}") end diff --git a/app/models/course_message.rb b/app/models/course_message.rb index 7774dbf0c..a3578d500 100644 --- a/app/models/course_message.rb +++ b/app/models/course_message.rb @@ -32,6 +32,6 @@ class CourseMessage < ApplicationRecord belong_container: course, extra: content.to_i == 2 ? '9' : '7', tiding_type: 'System', status: deal_status ) # 将申请消息置为已处理 - Tiding.where(trigger_user_id: user_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1) + Tiding.where(trigger_user_id: course_message_id, container_id: course_id, container_type: 'JoinCourse', status: 0).update_all(status: 1) end end \ No newline at end of file diff --git a/app/models/department.rb b/app/models/department.rb index 3b0672cce..2c537fd91 100644 --- a/app/models/department.rb +++ b/app/models/department.rb @@ -5,7 +5,7 @@ class Department < ApplicationRecord has_many :member_users, through: :department_members, source: :user has_many :user_extensions, dependent: :nullify - has_many :apply_add_departments + has_many :apply_add_departments, dependent: :destroy scope :without_deleted, -> { where(is_delete: false) } diff --git a/app/models/ec_course_student_score.rb b/app/models/ec_course_student_score.rb index 5b45e34a9..57d524b46 100644 --- a/app/models/ec_course_student_score.rb +++ b/app/models/ec_course_student_score.rb @@ -1,7 +1,6 @@ class EcCourseStudentScore < ApplicationRecord belongs_to :ec_year_student belongs_to :ec_course - belongs_to :ec_course_target has_many :ec_student_score_targets, dependent: :delete_all end \ No newline at end of file diff --git a/app/models/ec_course_support.rb b/app/models/ec_course_support.rb index a6ca96ea9..518fc1385 100644 --- a/app/models/ec_course_support.rb +++ b/app/models/ec_course_support.rb @@ -1,9 +1,10 @@ class EcCourseSupport < ApplicationRecord default_scope { order(position: :asc) } + alias_attribute :weights, :weigths + belongs_to :ec_course belongs_to :ec_graduation_subitem - # TODO: 将 ec_graduation_subitem_courses 移除,这个表作为关系表 has_one :ec_graduation_requirement_calculation, dependent: :destroy diff --git a/app/models/ec_course_target.rb b/app/models/ec_course_target.rb index 9b93cb73c..b13c81059 100644 --- a/app/models/ec_course_target.rb +++ b/app/models/ec_course_target.rb @@ -1,4 +1,3 @@ -# TODO:: change table column :weigths => :weight class EcCourseTarget < ApplicationRecord belongs_to :ec_course @@ -8,6 +7,8 @@ class EcCourseTarget < ApplicationRecord has_many :ec_course_achievement_methods, dependent: :destroy has_many :ec_achievement_evaluation_relates, dependent: :destroy + alias_attribute :weight, :weigths + validates :content, presence: true validates :standard_grade, numericality: { only_integer: true, greater_than: 0 } validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 } diff --git a/app/models/ec_graduation_requirement.rb b/app/models/ec_graduation_requirement.rb index d0f4195d0..f9c65e28e 100644 --- a/app/models/ec_graduation_requirement.rb +++ b/app/models/ec_graduation_requirement.rb @@ -1,4 +1,6 @@ class EcGraduationRequirement < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_year has_many :ec_graduation_subitems, dependent: :destroy @@ -7,5 +9,5 @@ class EcGraduationRequirement < ApplicationRecord validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } validates :content, presence: true - default_scope { order(position: :asc) } + accepts_nested_attributes_for :ec_graduation_subitems, allow_destroy: true end diff --git a/app/models/ec_major_school.rb b/app/models/ec_major_school.rb index 41a835f63..5cfc4df9e 100644 --- a/app/models/ec_major_school.rb +++ b/app/models/ec_major_school.rb @@ -12,6 +12,8 @@ class EcMajorSchool < ApplicationRecord scope :is_template, -> { where(template_major: true) } scope :not_template, -> { where(template_major: false) } + delegate :code, :name, to: :ec_major + # 是否为该专业管理员 def manager?(user) ec_major_school_users.exists?(user_id: user.id) diff --git a/app/models/ec_training_subitem.rb b/app/models/ec_training_subitem.rb index 0c9c61fbc..736e3f0da 100644 --- a/app/models/ec_training_subitem.rb +++ b/app/models/ec_training_subitem.rb @@ -1,4 +1,6 @@ class EcTrainingSubitem < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_training_objective has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy diff --git a/app/models/ec_year.rb b/app/models/ec_year.rb index 69ae4c291..6a3d97340 100644 --- a/app/models/ec_year.rb +++ b/app/models/ec_year.rb @@ -9,4 +9,11 @@ class EcYear < ApplicationRecord has_many :ec_graduation_requirements, dependent: :destroy has_many :ec_graduation_subitems, through: :ec_graduation_requirements has_many :ec_year_students, dependent: :destroy + + has_many :ec_course_users, dependent: :destroy + has_many :managers, through: :ec_course_users, source: :user + + def prev_year + self.class.find_by(year: year.to_i - 1) + end end diff --git a/app/models/graduation_work.rb b/app/models/graduation_work.rb index 235bfcac6..c0db92483 100644 --- a/app/models/graduation_work.rb +++ b/app/models/graduation_work.rb @@ -48,7 +48,7 @@ class GraduationWork < ApplicationRecord def delete_atta atta last_score = graduation_work_scores.where.not(score: nil).last - atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + (atta.author_id == self.user_id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on) end # 分班名 diff --git a/app/models/school.rb b/app/models/school.rb index 24de02496..387b6b5d8 100644 --- a/app/models/school.rb +++ b/app/models/school.rb @@ -17,6 +17,7 @@ class School < ApplicationRecord has_many :partners, dependent: :destroy has_many :apply_add_departments, dependent: :destroy + has_many :user_extensions, dependent: :nullify # 学校管理员 def manager?(user) diff --git a/app/models/student_graduation_topic.rb b/app/models/student_graduation_topic.rb index 50f150f92..b8f4dfbbb 100644 --- a/app/models/student_graduation_topic.rb +++ b/app/models/student_graduation_topic.rb @@ -21,7 +21,7 @@ class StudentGraduationTopic < ApplicationRecord def send_tiding self.tidings << Tiding.new(:user_id => self.graduation_topic.tea_id, :trigger_user_id => self.user_id, :parent_container_id => self.graduation_topic_id, :parent_container_type => "GraduationTopic", - :belong_container_id => self.graduation_topic.course_id, :belong_container_type => "Course", :viewed => 0, :status => 0, :tiding_type => "GraduationTopic") + :belong_container_id => self.graduation_topic.course_id, :belong_container_type => "Course", :viewed => 0, :status => 0, :tiding_type => "Apply") end # 学生名称 diff --git a/app/models/student_work.rb b/app/models/student_work.rb index 9c9efa17c..bbe0c0bed 100644 --- a/app/models/student_work.rb +++ b/app/models/student_work.rb @@ -106,7 +106,7 @@ class StudentWork < ApplicationRecord def delete_atta atta last_score = student_works_scores.where.not(score: nil).last - atta.author_id == user_id && (!last_score.present? || last_score.try(:created_at) < atta.created_on) + ((atta.author_id == self.user_id) && (last_score.blank? || last_score.try(:created_at) < atta.created_on)) end # 作品总体评价 diff --git a/app/models/subject.rb b/app/models/subject.rb index 6ecb5ed18..d5ea3f433 100644 --- a/app/models/subject.rb +++ b/app/models/subject.rb @@ -46,8 +46,7 @@ class Subject < ApplicationRecord # 挑战过路径的成员数(金课统计去重后的报名人数) def member_count - excellent && CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length > shixuns.pluck(:myshixuns_count).sum ? - CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum + excellent ? CourseMember.where(role: 4, course_id: courses.pluck(:id)).pluck(:user_id).length : shixuns.pluck(:myshixuns_count).sum end def all_score diff --git a/app/models/tiding.rb b/app/models/tiding.rb index d885f93fd..02692085a 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -22,4 +22,9 @@ class Tiding < ApplicationRecord value end + + def anonymous? + (container_type == 'StudentWorksScore' && extra.to_i == 3) || + (container_type == 'StudentWorksScoresAppeal' && parent_container_type == 'StudentWork' && tiding_type == 'System') + end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index 12759ea4d..1dc511513 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,663 +1,663 @@ -class User < ApplicationRecord - include Watchable - include Searchable::Dependents::User - - # Account statuses - STATUS_ANONYMOUS = 0 - STATUS_ACTIVE = 1 - STATUS_REGISTERED = 2 - STATUS_LOCKED = 3 - - # tpi tpm权限控制 - EDU_ADMIN = 1 # 超级管理员 - EDU_BUSINESS = 2 # 运营人员 - EDU_SHIXUN_MANAGER = 3 # 实训管理员 - EDU_SHIXUN_MEMBER = 4 # 实训成员 - EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师 - EDU_GAME_MANAGER = 6 # TPI的创建者 - EDU_TEACHER = 7 # 平台老师,但是未认证 - EDU_NORMAL = 8 # 普通用户 - - VALID_EMAIL_REGEX = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i - VALID_PHONE_REGEX = /^1\d{10}$/ - - LOGIN_LENGTH_LIMIT = 30 - MAIL_LENGTH_LMIT = 60 - - MIX_PASSWORD_LIMIT = 8 - - has_one :user_extension, dependent: :destroy - accepts_nested_attributes_for :user_extension, update_only: true - - has_many :memos, foreign_key: 'author_id' - has_many :created_shixuns, class_name: 'Shixun' - has_many :shixun_members, :dependent => :destroy - has_many :shixuns, :through => :shixun_members - has_many :myshixuns, :dependent => :destroy - has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训 - has_many :course_messages - has_many :courses, dependent: :destroy - - #试卷 - has_many :exercise_banks, :dependent => :destroy - has_many :exercise_users, :dependent => :destroy - has_many :exercise_answers, :dependent => :destroy #针对每个题目学生的答案 - has_many :exercise_shixun_answers, :dependent => :destroy #针对每个实训题目学生的答案 - has_many :exercise_answer_comments, :dependent => :destroy - has_many :exercises, :dependent => :destroy #创建的试卷 - - has_many :homework_banks, dependent: :destroy - - has_many :graduation_works, dependent: :destroy - - has_many :students_for_courses, foreign_key: :student_id, dependent: :destroy - has_one :onclick_time, :dependent => :destroy - - # 新版私信 - has_many :private_messages, dependent: :destroy - has_many :recent_contacts, through: :private_messages, source: :target - has_many :tidings, :dependent => :destroy - - has_many :games, :dependent => :destroy - has_many :created_subjects, foreign_key: :user_id, class_name: 'Subject' - has_many :subject_members, :dependent => :destroy - has_many :subjects, :through => :subject_members - has_many :grades, :dependent => :destroy - has_many :experiences, :dependent => :destroy - has_many :student_works, :dependent => :destroy - has_many :student_works_scores - has_many :student_works_evaluation_distributions - - # 毕业设计 - has_many :graduation_topics, :dependent => :destroy - has_many :student_graduation_topics, :dependent => :destroy - - # 题库 - has_many :question_banks, :dependent => :destroy - # 毕设任务题库 - has_many :gtask_banks, dependent: :destroy - has_many :gtopic_banks, dependent: :destroy - - #问卷 - has_many :course_members, :dependent => :destroy - has_many :poll_votes, :dependent => :destroy - has_many :poll_users, :dependent => :destroy - - has_many :messages,foreign_key: 'author_id',:dependent => :destroy - - has_many :journals_for_messages, :as => :jour, :dependent => :destroy - has_many :teacher_course_groups, :dependent => :destroy - - has_many :attachments,foreign_key: :author_id, :dependent => :destroy - - # 工程认证 - has_many :ec_school_users,:dependent => :destroy - has_many :schools, :through => :ec_school_users - - has_many :ec_major_school_users, :dependent => :destroy - has_many :ec_major_schools, :through => :ec_major_school_users - - has_many :ec_course_users - - has_many :department_members, dependent: :destroy #部门管理员 - - # 课堂 - has_many :student_course_members, -> { course_students }, class_name: 'CourseMember' - has_many :as_student_courses, through: :student_course_members, source: :course - has_many :manage_course_members, -> { teachers_and_admin }, class_name: 'CourseMember' - has_many :manage_courses, through: :manage_course_members, source: :course - - # 关注 - has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 - has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 - - # 认证 - has_many :apply_user_authentication - has_one :process_real_name_apply, -> { processing.real_name_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' - has_one :process_professional_apply, -> { processing.professional_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' - has_many :apply_actions, dependent: :destroy - has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction' - - has_many :attendances - - # 兴趣 - has_many :user_interests, dependent: :delete_all - has_many :interests, through: :user_interests, source: :repertoire - - # 众包 - has_many :project_packages, foreign_key: :creator_id, dependent: :destroy - has_many :bidding_users, dependent: :destroy - has_many :bidden_project_packages, through: :bidding_users, source: :project_package - - # 项目 - has_many :applied_projects, dependent: :destroy - - # 教学案例 - has_many :libraries, dependent: :destroy - - # 视频 - has_many :videos, dependent: :destroy - - # 客户管理 - belongs_to :partner, optional: true - - # Groups and active users - scope :active, lambda { where(status: STATUS_ACTIVE) } - - attr_accessor :password, :password_confirmation - - delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true - - before_save :update_hashed_password - - # - # validations - # - validates_presence_of :login, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }, case_sensitive: false - validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false - validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, case_sensitive: false - validates_uniqueness_of :phone, :if => Proc.new { |user| user.phone_changed? && user.phone.present? }, case_sensitive: false - validates_length_of :login, maximum: LOGIN_LENGTH_LIMIT - validates_length_of :mail, maximum: MAIL_LENGTH_LMIT - # validates_format_of :mail, with: VALID_EMAIL_REGEX, multiline: true - # validates_format_of :phone, with: VALID_PHONE_REGEX, multiline: true - validate :validate_password_length - - # validates :nickname, presence: true, length: { maximum: 10 } - # validates :lastname, presence: true - - # 删除自动登录的token,一旦退出下次会提示需要登录 - def delete_autologin_token(value) - Token.where(:user_id => id, :action => 'autologin', :value => value).delete_all - end - - def delete_session_token(value) - Token.where(:user_id => id, :action => 'session', :value => value).delete_all - end - - def git_mail - mail.blank? ? "#{login}@educoder.net" : mail - end - - # 学号 - def student_id - self.user_extension.try(:student_id) - end - - # 关注数 - def follow_count - Watcher.where(user_id: id, watchable_type: %w(Principal User)).count - # User.watched_by(id).count - end - - # 粉丝数 - def fan_count - Watcher.where(watchable_type: %w(Principal User), watchable_id: id).count - # watchers.count - end - - # 判断当前用户是否为老师 - def is_teacher? - self.user_extension.teacher? - end - - # 平台认证的老师 - def is_certification_teacher - self.user_extension.teacher? && self.professional_certification - end - - def certification_teacher? - professional_certification? && user_extension.teacher? - end - - # 判断用户的身份 - def identity - ue = self.user_extension - unless ue.blank? - if ue.teacher? - ue.technical_title ? ue.technical_title : "老师" - elsif ue.student? - "学生" - else - ue.technical_title ? ue.technical_title : "专业人士" - end - end - end - - # 判断当前用户是否通过职业认证 - def pro_certification? - professional_certification - end - - # 用户的学校名称 - def school_name - user_extension&.school&.name || '' - end - - # 用户的学院名称 - def department_name - user_extension&.department&.name || '' - end - - # 课堂的老师(创建者、老师、助教) - def teacher_of_course?(course) - course.course_members.exists?(user_id: id, role: [1,2,3], is_active: 1) || admin? || business? - end - - # 课堂的老师(创建者、老师、助教),不用考虑当前身份 - def teacher_of_course_non_active?(course) - course.course_members.exists?(user_id: id, role: [1,2,3]) - end - - # 是否是教师,课堂管理员或者超级管理员 - def teacher_or_admin?(course) - course.course_members.exists?(user_id: id, role: [1,2], is_active: 1) || admin? || business? - end - - # 课堂的创建者(考虑到多重身份的用户) - def creator_of_course?(course) - course.course_members.exists?(user_id: id, role: 1, is_active: 1) || admin? || business? - end - - # 课堂的学生 - def student_of_course?(course) - course.course_members.exists?(user_id: id, role: %i[STUDENT]) - end - - # 课堂成员 - def member_of_course?(course) - course&.course_members.exists?(user_id: id) - end - - # 实训路径管理员 - def creator_of_subject?(subject) - subject.user_id == id || admin? - end - - # 实训路径:合作者、admin - def manager_of_subject?(subject) - subject.subject_members.exists?(user_id: id, role: [1,2]) || admin? - end - - # 实训管理员:实训合作者、admin - def manager_of_shixun?(shixun) - shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin? || business? - end - - # 实训管理员 - def creator_of_shixun?(shixun) - id == shixun.user_id - end - - # 实训的合作者 - def member_of_shixun?(shixun) - #self.shixun_members.where(:role => 2, :shixun_id => shixun.id).present? - shixun.shixun_members.exists?(role: 2, user_id: id) - end - - # TPI的创建者 - def creator_of_game?(game) - id == game.user_id - end - - # 用户账号状态 - def active? - status == STATUS_ACTIVE - end - - def registered? - status == STATUS_REGISTERED - end - - def locked? - status == STATUS_LOCKED - end - - def activate - self.status = STATUS_ACTIVE - end - - def register - self.status = STATUS_REGISTERED - end - - def lock - self.status = STATUS_LOCKED - end - - def activate! - update_attribute(:status, STATUS_ACTIVE) - end - - def register! - update_attribute(:status, STATUS_REGISTERED) - end - - def lock! - update_attribute(:status, STATUS_LOCKED) - end - - # 课程用户身份 - def course_identity(course) - if !logged? - Course::Anonymous - elsif admin? - Course::ADMIN - elsif business? - Course::BUSINESS - else - role = course.course_members.find_by(user_id: id, is_active: 1)&.role - case role - when nil then Course::NORMAL - when 'CREATOR' then Course::CREATOR - when 'PROFESSOR' then Course::PROFESSOR - when 'STUDENT' then Course::STUDENT - when 'ASSISTANT_PROFESSOR' then Course::ASSISTANT_PROFESSOR - end - end - end - - # 实训用户身份 - def shixun_identity(shixun) - @identity = - if admin? - User::EDU_ADMIN - elsif business? - User::EDU_BUSINESS - elsif creator_of_shixun?(shixun) - User::EDU_SHIXUN_MANAGER - elsif member_of_shixun?(shixun) - User::EDU_SHIXUN_MEMBER - elsif is_certification_teacher - User::EDU_CERTIFICATION_TEACHER - elsif is_teacher? - User::EDU_TEACHER - else - User::EDU_NORMAL - end - return @identity - end - - # tpi的用户身份 - def game_identity(game) - shixun = game.myshixun.shixun - @identity = - if admin? - User::EDU_ADMIN - elsif business? - User::EDU_BUSINESS - elsif creator_of_shixun?(shixun) - User::EDU_SHIXUN_MANAGER - elsif member_of_shixun?(shixun) - User::EDU_SHIXUN_MEMBER - elsif is_certification_teacher - User::EDU_CERTIFICATION_TEACHER - elsif creator_of_game?(game) - User::EDU_GAME_MANAGER - elsif is_teacher? - User::EDU_TEACHER - else - User::EDU_NORMAL - end - return @identity - end - - # 我的实训 - def my_shixuns - shixun_ids = shixun_members.pluck(:shixun_id) + myshixuns.pluck(:shixun_id) - Shixun.where(:id => shixun_ids).visible - end - - # 用户是否有权限查看实训 - # 1、实训删除只有管理员能看到 - # 2、实训隐藏了只有管理员、实训合作者能看到 - # 3、如果有限制学校范围,则学校的用户、管理员、实训合作者能看到 - def shixun_permission(shixun) - case shixun.status - when -1 # 软删除只有管理员能访问 - admin? - when 0, 1, 3 # 申请发布或者已关闭的实训,只有实训管理员可以访问 - manager_of_shixun?(shixun) - when 2 - if shixun.hidden - manager_of_shixun?(shixun) - else - shixun.use_scope == 0 || manager_of_shixun?(shixun) || shixun.shixun_schools.exists?(school_id: school_id) - end - end - end - - # 用户在平台名称的显示方式 - def full_name - return '游客' unless logged? - - name = show_realname? ? lastname + firstname : nickname - name.blank? ? (nickname.blank? ? login : nickname) : name - end - - # 用户的真实姓名(不考虑用户是否隐藏了真实姓名,课堂模块都用真实姓名) - def real_name - return '游客' unless logged? - name = lastname + firstname - name = name.blank? ? (nickname.blank? ? login : nickname) : name - name.gsub(/\s+/, '').strip #6.11 -hs - end - - def only_real_name - "#{lastname}#{firstname}" - end - - # 用户是否选题毕设课题 - def selected_topic?(topic) - student_graduation_topics.where(graduation_topic_id: topic.id).last.try(:status) - end - - def click_time - click_time = OnclickTime.find_by(user_id: id) || OnclickTime.create(user_id: id, onclick_time: created_on) - click_time.onclick_time - end - - def manager_of_memo?(memo) - id == memo.author_id || admin? || business? - end - - # 是否是项目管理者 - def manager_of_project?(project) - project.project_members.where(user_id: id).count > 0 - end - - def logged? - true - end - - def active? - status == STATUS_ACTIVE - end - - def locked? - status == STATUS_LOCKED - end - - def phone_binded? - phone.present? - end - - def self.current=(user) - Thread.current[:current_user] = user - end - - def self.current - Thread.current[:current_user] ||= User.anonymous - end - - def self.anonymous - anonymous_user = AnonymousUser.unscoped.take - if anonymous_user.nil? - anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '', - mail: '358551897@qq.com', phone: '13333333333', status: 0) - raise "Unable to create the anonymous user: error_info:#{anonymous_user.errors.messages}" if anonymous_user.new_record? - end - anonymous_user - end - - # Returns the user who matches the given autologin +key+ or nil - def self.try_to_autologin(key) - user = Token.find_active_user('autologin', key) - user.update(last_login_on: Time.now) if user - user - end - - def self.hash_password(clear_password) - Digest::SHA1.hexdigest(clear_password || "") - end - - def check_password?(clear_password) - # Preventing Timing Attack - ActiveSupport::SecurityUtils.secure_compare( - User.hash_password("#{salt}#{User.hash_password clear_password}"), - hashed_password - ) - end - - # 工程认证的学校 - def ec_school - school_id = self.ec_school_users.pluck(:school_id).first || - self.ec_major_schools.pluck(:school_id).first || - (self.ec_course_users.first && self.ec_course_users.first.try(:ec_course).try(:ec_year).try(:ec_major_school).try(:school_id)) - end - - # 登录,返回用户名与密码匹配的用户 - def self.try_to_login(login, password) - login = login.to_s.strip - password = password.to_s - - # Make sure no one can sign in with an empty login or password - return nil if login.empty? || password.empty? - if (login =~ VALID_EMAIL_REGEX) - user = find_by_mail(login) - elsif (login =~ VALID_PHONE_REGEX) - user = find_by_phone(login) - else - user = find_by_login(login) - end - - user - rescue => text - raise text - end - - def show_real_name - name = lastname + firstname - if name.blank? - nickname.blank? ? login : nickname - else - name - end - end - - def update_hashed_password - if password - salt_password(password) - end - end - - def salt_password(clear_password) - self.salt = User.generate_salt - self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") - end - - def self.generate_salt - Educoder::Utils.random_hex(16) - end - - # 全部已认证 - def all_certified? - authentication? && professional_certification? - end - - # 是否绑定邮箱 - def email_binded? - mail.present? - end - - # 学院的url标识 - def college_identifier - Department.find_by_id(department_members.pluck(:department_id).first)&.identifier - end - - # 是否能申请试用 - def can_apply_trial? - return false if certification == 1 - - apply = ApplyAction.order(created_at: :desc).find_by(user_id: id, container_type: 'TrialAuthorization') - - apply.present? && !apply.status.zero? - end - - # 是否已经签到 - def attendance_signed? - attendance = Attendance.find_by(user_id: id) - - attendance.present? && Util.days_between(Time.zone.now, attendance.created_at).zero? - end - - # 明日签到金币 - def tomorrow_attendance_gold - Attendance.find_by(user_id: id)&.next_gold || 60 # 基础50,连续签到+10 - end - - def admin_or_business? - admin? || business? - end - - protected - def validate_password_length - # 管理员的初始密码是5位 - if password.present? && password.size < MIX_PASSWORD_LIMIT && !User.current.admin? - raise("密码长度不能低于#{MIX_PASSWORD_LIMIT}位") - end - end -end - - -class AnonymousUser < User - validate :validate_anonymous_uniqueness, :on => :create - - def validate_anonymous_uniqueness - # There should be only one AnonymousUser in the database - errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists? - end - - def available_custom_fields - [] - end - - # Overrides a few properties - def logged?; false end - def admin; false end - def name(*args); I18n.t(:label_user_anonymous) end - # def mail=(*args); nil end - # def mail; nil end - def time_zone; nil end - def rss_key; nil end - - - def membership(*args) - nil - end - - def member_of?(*args) - false - end - - # Anonymous user can not be destroyed - def destroy - false - end - - protected - - def instantiate_email_address - end - -end +class User < ApplicationRecord + include Watchable + include Searchable::Dependents::User + + # Account statuses + STATUS_ANONYMOUS = 0 + STATUS_ACTIVE = 1 + STATUS_REGISTERED = 2 + STATUS_LOCKED = 3 + + # tpi tpm权限控制 + EDU_ADMIN = 1 # 超级管理员 + EDU_BUSINESS = 2 # 运营人员 + EDU_SHIXUN_MANAGER = 3 # 实训管理员 + EDU_SHIXUN_MEMBER = 4 # 实训成员 + EDU_CERTIFICATION_TEACHER = 5 # 平台认证的老师 + EDU_GAME_MANAGER = 6 # TPI的创建者 + EDU_TEACHER = 7 # 平台老师,但是未认证 + EDU_NORMAL = 8 # 普通用户 + + VALID_EMAIL_REGEX = /^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/i + VALID_PHONE_REGEX = /^1\d{10}$/ + + LOGIN_LENGTH_LIMIT = 30 + MAIL_LENGTH_LMIT = 60 + + MIX_PASSWORD_LIMIT = 8 + + has_one :user_extension, dependent: :destroy + accepts_nested_attributes_for :user_extension, update_only: true + + has_many :memos, foreign_key: 'author_id' + has_many :created_shixuns, class_name: 'Shixun' + has_many :shixun_members, :dependent => :destroy + has_many :shixuns, :through => :shixun_members + has_many :myshixuns, :dependent => :destroy + has_many :study_shixuns, through: :myshixuns, source: :shixun # 已学习的实训 + has_many :course_messages + has_many :courses, dependent: :destroy + + #试卷 + has_many :exercise_banks, :dependent => :destroy + has_many :exercise_users, :dependent => :destroy + has_many :exercise_answers, :dependent => :destroy #针对每个题目学生的答案 + has_many :exercise_shixun_answers, :dependent => :destroy #针对每个实训题目学生的答案 + has_many :exercise_answer_comments, :dependent => :destroy + has_many :exercises, :dependent => :destroy #创建的试卷 + + has_many :homework_banks, dependent: :destroy + + has_many :graduation_works, dependent: :destroy + + has_many :students_for_courses, foreign_key: :student_id, dependent: :destroy + has_one :onclick_time, :dependent => :destroy + + # 新版私信 + has_many :private_messages, dependent: :destroy + has_many :recent_contacts, through: :private_messages, source: :target + has_many :tidings, :dependent => :destroy + + has_many :games, :dependent => :destroy + has_many :created_subjects, foreign_key: :user_id, class_name: 'Subject' + has_many :subject_members, :dependent => :destroy + has_many :subjects, :through => :subject_members + has_many :grades, :dependent => :destroy + has_many :experiences, :dependent => :destroy + has_many :student_works, :dependent => :destroy + has_many :student_works_scores + has_many :student_works_evaluation_distributions + + # 毕业设计 + has_many :graduation_topics, :dependent => :destroy + has_many :student_graduation_topics, :dependent => :destroy + + # 题库 + has_many :question_banks, :dependent => :destroy + # 毕设任务题库 + has_many :gtask_banks, dependent: :destroy + has_many :gtopic_banks, dependent: :destroy + + #问卷 + has_many :course_members, :dependent => :destroy + has_many :poll_votes, :dependent => :destroy + has_many :poll_users, :dependent => :destroy + + has_many :messages,foreign_key: 'author_id',:dependent => :destroy + + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + has_many :teacher_course_groups, :dependent => :destroy + + has_many :attachments,foreign_key: :author_id, :dependent => :destroy + + # 工程认证 + has_many :ec_school_users,:dependent => :destroy + has_many :schools, :through => :ec_school_users + + has_many :ec_major_school_users, :dependent => :destroy + has_many :ec_major_schools, :through => :ec_major_school_users + + has_many :ec_course_users + + has_many :department_members, dependent: :destroy #部门管理员 + + # 课堂 + has_many :student_course_members, -> { course_students }, class_name: 'CourseMember' + has_many :as_student_courses, through: :student_course_members, source: :course + has_many :manage_course_members, -> { teachers_and_admin }, class_name: 'CourseMember' + has_many :manage_courses, through: :manage_course_members, source: :course + + # 关注 + has_many :be_watchers, foreign_key: :user_id, dependent: :destroy # 我的关注 + has_many :be_watcher_users, through: :be_watchers, dependent: :destroy # 我关注的用户 + + # 认证 + has_many :apply_user_authentication + has_one :process_real_name_apply, -> { processing.real_name_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' + has_one :process_professional_apply, -> { processing.professional_auth.order(created_at: :desc) }, class_name: 'ApplyUserAuthentication' + has_many :apply_actions, dependent: :destroy + has_many :trail_auth_apply_actions, -> { where(container_type: 'TrialAuthorization') }, class_name: 'ApplyAction' + + has_many :attendances + + # 兴趣 + has_many :user_interests, dependent: :delete_all + has_many :interests, through: :user_interests, source: :repertoire + + # 众包 + has_many :project_packages, foreign_key: :creator_id, dependent: :destroy + has_many :bidding_users, dependent: :destroy + has_many :bidden_project_packages, through: :bidding_users, source: :project_package + + # 项目 + has_many :applied_projects, dependent: :destroy + + # 教学案例 + has_many :libraries, dependent: :destroy + + # 视频 + has_many :videos, dependent: :destroy + + # 客户管理 + belongs_to :partner, optional: true + + # Groups and active users + scope :active, lambda { where(status: STATUS_ACTIVE) } + + attr_accessor :password, :password_confirmation + + delegate :gender, :department_id, :school_id, :location, :location_city, :technical_title, to: :user_extension, allow_nil: true + + before_save :update_hashed_password + + # + # validations + # + validates_presence_of :login, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }, case_sensitive: false + validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, case_sensitive: false + validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, case_sensitive: false + validates_uniqueness_of :phone, :if => Proc.new { |user| user.phone_changed? && user.phone.present? }, case_sensitive: false + validates_length_of :login, maximum: LOGIN_LENGTH_LIMIT + validates_length_of :mail, maximum: MAIL_LENGTH_LMIT + # validates_format_of :mail, with: VALID_EMAIL_REGEX, multiline: true + # validates_format_of :phone, with: VALID_PHONE_REGEX, multiline: true + validate :validate_password_length + + # validates :nickname, presence: true, length: { maximum: 10 } + # validates :lastname, presence: true + + # 删除自动登录的token,一旦退出下次会提示需要登录 + def delete_autologin_token(value) + Token.where(:user_id => id, :action => 'autologin', :value => value).delete_all + end + + def delete_session_token(value) + Token.where(:user_id => id, :action => 'session', :value => value).delete_all + end + + def git_mail + mail.blank? ? "#{login}@educoder.net" : mail + end + + # 学号 + def student_id + self.user_extension.try(:student_id) + end + + # 关注数 + def follow_count + Watcher.where(user_id: id, watchable_type: %w(Principal User)).count + # User.watched_by(id).count + end + + # 粉丝数 + def fan_count + Watcher.where(watchable_type: %w(Principal User), watchable_id: id).count + # watchers.count + end + + # 判断当前用户是否为老师 + def is_teacher? + self.user_extension.teacher? + end + + # 平台认证的老师 + def is_certification_teacher + self.user_extension.teacher? && self.professional_certification + end + + def certification_teacher? + professional_certification? && user_extension.teacher? + end + + # 判断用户的身份 + def identity + ue = self.user_extension + unless ue.blank? + if ue.teacher? + ue.technical_title ? ue.technical_title : "老师" + elsif ue.student? + "学生" + else + ue.technical_title ? ue.technical_title : "专业人士" + end + end + end + + # 判断当前用户是否通过职业认证 + def pro_certification? + professional_certification + end + + # 用户的学校名称 + def school_name + user_extension&.school&.name || '' + end + + # 用户的学院名称 + def department_name + user_extension&.department&.name || '' + end + + # 课堂的老师(创建者、老师、助教) + def teacher_of_course?(course) + course.course_members.exists?(user_id: id, role: [1,2,3], is_active: 1) || admin? || business? + end + + # 课堂的老师(创建者、老师、助教),不用考虑当前身份 + def teacher_of_course_non_active?(course) + course.course_members.exists?(user_id: id, role: [1,2,3]) + end + + # 是否是教师,课堂管理员或者超级管理员 + def teacher_or_admin?(course) + course.course_members.exists?(user_id: id, role: [1,2], is_active: 1) || admin? || business? + end + + # 课堂的创建者(考虑到多重身份的用户) + def creator_of_course?(course) + course.course_members.exists?(user_id: id, role: 1, is_active: 1) || admin? || business? + end + + # 课堂的学生 + def student_of_course?(course) + course.course_members.exists?(user_id: id, role: %i[STUDENT]) + end + + # 课堂成员 + def member_of_course?(course) + course&.course_members.exists?(user_id: id) + end + + # 实训路径管理员 + def creator_of_subject?(subject) + subject.user_id == id || admin? + end + + # 实训路径:合作者、admin + def manager_of_subject?(subject) + subject.subject_members.exists?(user_id: id, role: [1,2]) || admin? + end + + # 实训管理员:实训合作者、admin + def manager_of_shixun?(shixun) + shixun.shixun_members.exists?(role: [1,2], user_id: id) || admin? || business? + end + + # 实训管理员 + def creator_of_shixun?(shixun) + id == shixun.user_id + end + + # 实训的合作者 + def member_of_shixun?(shixun) + #self.shixun_members.where(:role => 2, :shixun_id => shixun.id).present? + shixun.shixun_members.exists?(role: 2, user_id: id) + end + + # TPI的创建者 + def creator_of_game?(game) + id == game.user_id + end + + # 用户账号状态 + def active? + status == STATUS_ACTIVE + end + + def registered? + status == STATUS_REGISTERED + end + + def locked? + status == STATUS_LOCKED + end + + def activate + self.status = STATUS_ACTIVE + end + + def register + self.status = STATUS_REGISTERED + end + + def lock + self.status = STATUS_LOCKED + end + + def activate! + update_attribute(:status, STATUS_ACTIVE) + end + + def register! + update_attribute(:status, STATUS_REGISTERED) + end + + def lock! + update_attribute(:status, STATUS_LOCKED) + end + + # 课程用户身份 + def course_identity(course) + if !logged? + Course::Anonymous + elsif admin? + Course::ADMIN + elsif business? + Course::BUSINESS + else + role = course.course_members.find_by(user_id: id, is_active: 1)&.role + case role + when nil then Course::NORMAL + when 'CREATOR' then Course::CREATOR + when 'PROFESSOR' then Course::PROFESSOR + when 'STUDENT' then Course::STUDENT + when 'ASSISTANT_PROFESSOR' then Course::ASSISTANT_PROFESSOR + end + end + end + + # 实训用户身份 + def shixun_identity(shixun) + @identity = + if admin? + User::EDU_ADMIN + elsif business? + User::EDU_BUSINESS + elsif creator_of_shixun?(shixun) + User::EDU_SHIXUN_MANAGER + elsif member_of_shixun?(shixun) + User::EDU_SHIXUN_MEMBER + elsif is_certification_teacher + User::EDU_CERTIFICATION_TEACHER + elsif is_teacher? + User::EDU_TEACHER + else + User::EDU_NORMAL + end + return @identity + end + + # tpi的用户身份 + def game_identity(game) + shixun = game.myshixun.shixun + @identity = + if admin? + User::EDU_ADMIN + elsif business? + User::EDU_BUSINESS + elsif creator_of_shixun?(shixun) + User::EDU_SHIXUN_MANAGER + elsif member_of_shixun?(shixun) + User::EDU_SHIXUN_MEMBER + elsif is_certification_teacher + User::EDU_CERTIFICATION_TEACHER + elsif creator_of_game?(game) + User::EDU_GAME_MANAGER + elsif is_teacher? + User::EDU_TEACHER + else + User::EDU_NORMAL + end + return @identity + end + + # 我的实训 + def my_shixuns + shixun_ids = shixun_members.pluck(:shixun_id) + myshixuns.pluck(:shixun_id) + Shixun.where(:id => shixun_ids).visible + end + + # 用户是否有权限查看实训 + # 1、实训删除只有管理员能看到 + # 2、实训隐藏了只有管理员、实训合作者能看到 + # 3、如果有限制学校范围,则学校的用户、管理员、实训合作者能看到 + def shixun_permission(shixun) + case shixun.status + when -1 # 软删除只有管理员能访问 + admin? + when 0, 1, 3 # 申请发布或者已关闭的实训,只有实训管理员可以访问 + manager_of_shixun?(shixun) + when 2 + if shixun.hidden + manager_of_shixun?(shixun) + else + shixun.use_scope == 0 || manager_of_shixun?(shixun) || shixun.shixun_schools.exists?(school_id: school_id) + end + end + end + + # 用户在平台名称的显示方式 + def full_name + return '游客' unless logged? + + name = show_realname? ? lastname + firstname : nickname + name.blank? ? (nickname.blank? ? login : nickname) : name + end + + # 用户的真实姓名(不考虑用户是否隐藏了真实姓名,课堂模块都用真实姓名) + def real_name + return '游客' unless logged? + name = lastname + firstname + name = name.blank? ? (nickname.blank? ? login : nickname) : name + name.gsub(/\s+/, '').strip #6.11 -hs + end + + def only_real_name + "#{lastname}#{firstname}" + end + + # 用户是否选题毕设课题 + def selected_topic?(topic) + student_graduation_topics.where(graduation_topic_id: topic.id).last.try(:status) + end + + def click_time + click_time = OnclickTime.find_by(user_id: id) || OnclickTime.create(user_id: id, onclick_time: created_on) + click_time.onclick_time + end + + def manager_of_memo?(memo) + id == memo.author_id || admin? || business? + end + + # 是否是项目管理者 + def manager_of_project?(project) + project.project_members.where(user_id: id).count > 0 + end + + def logged? + true + end + + def active? + status == STATUS_ACTIVE + end + + def locked? + status == STATUS_LOCKED + end + + def phone_binded? + phone.present? + end + + def self.current=(user) + Thread.current[:current_user] = user + end + + def self.current + Thread.current[:current_user] ||= User.anonymous + end + + def self.anonymous + anonymous_user = AnonymousUser.unscoped.take + if anonymous_user.nil? + anonymous_user = AnonymousUser.unscoped.create(lastname: 'Anonymous', firstname: '', login: '', + mail: '358551897@qq.com', phone: '13333333333', status: 0) + raise "Unable to create the anonymous user: error_info:#{anonymous_user.errors.messages}" if anonymous_user.new_record? + end + anonymous_user + end + + # Returns the user who matches the given autologin +key+ or nil + def self.try_to_autologin(key) + user = Token.find_active_user('autologin', key) + user.update(last_login_on: Time.now) if user + user + end + + def self.hash_password(clear_password) + Digest::SHA1.hexdigest(clear_password || "") + end + + def check_password?(clear_password) + # Preventing Timing Attack + ActiveSupport::SecurityUtils.secure_compare( + User.hash_password("#{salt}#{User.hash_password clear_password}"), + hashed_password + ) + end + + # 工程认证的学校 + def ec_school + school_id = self.ec_school_users.pluck(:school_id).first || + self.ec_major_schools.pluck(:school_id).first || + (self.ec_course_users.first && self.ec_course_users.first.try(:ec_course).try(:ec_year).try(:ec_major_school).try(:school_id)) + end + + # 登录,返回用户名与密码匹配的用户 + def self.try_to_login(login, password) + login = login.to_s.strip + password = password.to_s + + # Make sure no one can sign in with an empty login or password + return nil if login.empty? || password.empty? + if (login =~ VALID_EMAIL_REGEX) + user = find_by_mail(login) + elsif (login =~ VALID_PHONE_REGEX) + user = find_by_phone(login) + else + user = find_by_login(login) + end + + user + rescue => text + raise text + end + + def show_real_name + name = lastname + firstname + if name.blank? + nickname.blank? ? login : nickname + else + name + end + end + + def update_hashed_password + if password + salt_password(password) + end + end + + def salt_password(clear_password) + self.salt = User.generate_salt + self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") + end + + def self.generate_salt + Educoder::Utils.random_hex(16) + end + + # 全部已认证 + def all_certified? + authentication? && professional_certification? + end + + # 是否绑定邮箱 + def email_binded? + mail.present? + end + + # 学院的url标识 + def college_identifier + Department.find_by_id(department_members.pluck(:department_id).first)&.identifier + end + + # 是否能申请试用 + def can_apply_trial? + return false if certification == 1 + + apply = ApplyAction.order(created_at: :desc).find_by(user_id: id, container_type: 'TrialAuthorization') + + apply.present? && !apply.status.zero? + end + + # 是否已经签到 + def attendance_signed? + attendance = Attendance.find_by(user_id: id) + + attendance.present? && Util.days_between(Time.zone.now, attendance.created_at).zero? + end + + # 明日签到金币 + def tomorrow_attendance_gold + Attendance.find_by(user_id: id)&.next_gold || 60 # 基础50,连续签到+10 + end + + def admin_or_business? + admin? || business? + end + + protected + def validate_password_length + # 管理员的初始密码是5位 + if password.present? && password.size < MIX_PASSWORD_LIMIT && !User.current.admin? + raise("密码长度不能低于#{MIX_PASSWORD_LIMIT}位") + end + end +end + + +class AnonymousUser < User + validate :validate_anonymous_uniqueness, :on => :create + + def validate_anonymous_uniqueness + # There should be only one AnonymousUser in the database + errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists? + end + + def available_custom_fields + [] + end + + # Overrides a few properties + def logged?; false end + def admin; false end + def name(*args); I18n.t(:label_user_anonymous) end + # def mail=(*args); nil end + # def mail; nil end + def time_zone; nil end + def rss_key; nil end + + + def membership(*args) + nil + end + + def member_of?(*args) + false + end + + # Anonymous user can not be destroyed + def destroy + false + end + + protected + + def instantiate_email_address + end + +end diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb index 98afcb165..0a2249308 100644 --- a/app/models/user_extension.rb +++ b/app/models/user_extension.rb @@ -1,6 +1,6 @@ class UserExtension < ApplicationRecord # identity 0: 教师教授 1: 学生, 2: 专业人士, 3: 开发者 - enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, cnmooc: 4, unselect: -1 } + enum identity: { teacher: 0, student: 1, professional: 2, developer: 3, enterprise: 4, unselect: -1 } belongs_to :user, touch: true belongs_to :school, optional: true diff --git a/app/queries/admins/school_query.rb b/app/queries/admins/school_query.rb new file mode 100644 index 000000000..7361588c4 --- /dev/null +++ b/app/queries/admins/school_query.rb @@ -0,0 +1,23 @@ +class Admins::SchoolQuery < ApplicationQuery + include CustomSortable + + attr_reader :params + + sort_columns :users_count, :created_at, default_by: :created_at, default_direction: :desc + + def initialize(params) + @params = params + end + + def call + schools = School.all + + keyword = strip_param(:keyword) + schools = schools.where('schools.name LIKE ?', "%#{keyword}%") if keyword + + schools = schools.joins(:user_extensions).group(:id) + schools = schools.select('schools.*, COUNT(*) AS users_count') + + custom_sort schools, params[:sort_by], params[:sort_direction] + end +end \ No newline at end of file diff --git a/app/queries/application_query.rb b/app/queries/application_query.rb index 3a92cc6e8..c66af94c0 100644 --- a/app/queries/application_query.rb +++ b/app/queries/application_query.rb @@ -1,3 +1,9 @@ class ApplicationQuery include Callable + + private + + def strip_param(key) + params[key].to_s.strip.presence + end end \ No newline at end of file diff --git a/app/queries/user_query.rb b/app/queries/user_query.rb new file mode 100644 index 000000000..326665fe9 --- /dev/null +++ b/app/queries/user_query.rb @@ -0,0 +1,28 @@ +class UserQuery < ApplicationQuery + attr_reader :params + + def initialize(params) + @params = params + end + + def call + users = User.where(type: 'User') + + # 真实姓名 + if name = strip_param(:name) + users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%") + end + + # 单位名称 + if school = strip_param(:school) + users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school}%") + end + + # 职业 + if (identity = strip_param(:identity)) && UserExtension.identities.keys.include?(identity) + users = users.joins(:user_extension).where(user_extensions: { identity: identity }) + end + + users + end +end \ No newline at end of file diff --git a/app/services/ecs/copy_ec_year_service.rb b/app/services/ecs/copy_ec_year_service.rb index 87cbe0845..462681eba 100644 --- a/app/services/ecs/copy_ec_year_service.rb +++ b/app/services/ecs/copy_ec_year_service.rb @@ -1,4 +1,4 @@ -class CopyEcYearService < ApplicationService +class Ecs::CopyEcYearService < ApplicationService attr_reader :major_school, :to_year def initialize(major_school, year) diff --git a/app/services/ecs/create_course_service.rb b/app/services/ecs/create_course_service.rb index dba162189..3e3828c6f 100644 --- a/app/services/ecs/create_course_service.rb +++ b/app/services/ecs/create_course_service.rb @@ -27,7 +27,7 @@ class Ecs::CreateCourseService < ApplicationService private def create_default_score_levels!(ec_course) - EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position) do |worker| + EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position, :created_at, :updated_at) do |worker| [ { ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 }, { ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 }, diff --git a/app/services/ecs/create_major_manager_service.rb b/app/services/ecs/create_major_manager_service.rb index befe80706..c955bffed 100644 --- a/app/services/ecs/create_major_manager_service.rb +++ b/app/services/ecs/create_major_manager_service.rb @@ -3,29 +3,30 @@ class Ecs::CreateMajorManagerService < ApplicationService MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制 - attr_reader :major_school, :user_id + attr_reader :major_school, :user_ids - def initialize(major_school, user_id) + def initialize(major_school, user_ids) @major_school = major_school - @user_id = user_id + @user_ids = user_ids end def call raise Error, '示例专业不能添加管理员' if major_school.template_major? - user = User.find_by(id: params[:user_id]) - raise Error, '该用户不存在' if user.blank? + @user_ids = User.where(id: user_ids).pluck(:id) - if major_school.ec_major_school_users.exists?(user_id: user.id) - raise Error, '该用户已经是该专业的管理员了' + if major_school.ec_major_school_users.exists?(user_id: user_ids) + raise Error, '所选用户中存在该专业的管理员' end - if major_school.ec_major_school_users.count >= MAJOR_MANAGER_COUNT_LIMIT - raise Error, '该专业管理员数量已达上限' + if major_school.ec_major_school_users.count + user_ids.count > MAJOR_MANAGER_COUNT_LIMIT + raise Error, "该专业管理员数量超过上限(#{MAJOR_MANAGER_COUNT_LIMIT}人)" end - major_school.ec_major_school_users.create!(user: user) - - user + ActiveRecord::Base.transaction do + user_ids.each do |user_id| + major_school.ec_major_school_users.create!(user_id: user_id) + end + end end end \ No newline at end of file diff --git a/app/services/ecs/create_training_objective_service.rb b/app/services/ecs/create_training_objective_service.rb index c3dc3c8a6..effbf5420 100644 --- a/app/services/ecs/create_training_objective_service.rb +++ b/app/services/ecs/create_training_objective_service.rb @@ -11,13 +11,16 @@ class Ecs::CreateTrainingObjectiveService < ApplicationService def call training_objective.content = params[:content].to_s.strip - attributes = build_accepts_nested_attributes( - training_objective, - training_objective.ec_training_subitems, - params[:training_subitems], - &method(:training_subitem_param_handler) - ) - training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + if params.key?(:training_subitems) + attributes = build_accepts_nested_attributes( + training_objective, + training_objective.ec_training_subitems, + params[:training_subitems], + &method(:training_subitem_param_handler) + ) + attributes.each_with_index { |attr, index| attr[:position] = index + 1 } + training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + end training_objective.save! training_objective diff --git a/app/services/ecs/import_student_service.rb b/app/services/ecs/import_student_service.rb index 9014e221c..8c16bd6e5 100644 --- a/app/services/ecs/import_student_service.rb +++ b/app/services/ecs/import_student_service.rb @@ -1,18 +1,17 @@ class Ecs::ImportStudentService < ApplicationService Error = Class.new(StandardError) - attr_reader :ec_year, :attachment + attr_reader :ec_year, :params - def initialize(ec_year, attachment_id) - @ec_year = ec_year - @attachment = Attachment.find_by(id: attachment_id) + def initialize(ec_year, params) + @ec_year = ec_year + @params = params end def call - raise Error, '文件不存在' if attachment.blank? + raise Error, '文件不存在' if params[:file].blank? || !params[:file].is_a?(ActionDispatch::Http::UploadedFile) - path = attachment.diskfile - excel = Ecs::ImportStudentExcel.new(path) + excel = Ecs::ImportStudentExcel.new(params[:file].path) success_count = 0 EcYearStudent.bulk_insert(:student_id, :name, :created_at, :updated_at) do |worker| diff --git a/app/services/ecs/query_course_evaluation_service.rb b/app/services/ecs/query_course_evaluation_service.rb index 8c76da438..22e0ce1f4 100644 --- a/app/services/ecs/query_course_evaluation_service.rb +++ b/app/services/ecs/query_course_evaluation_service.rb @@ -17,12 +17,12 @@ class Ecs::QueryCourseEvaluationService < ApplicationService end def graduation_subitem_evaluations - student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) + student_scores = ec_course.ec_course_student_scores.joins(ec_student_score_targets: :ec_course_target).group(:ec_course_target_id) student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') student_score_map = student_scores.group_by { |item| item.ec_course_target_id } subitem_targets = ec_course.ec_graduation_subitem_course_targets - .includes(ec_graduation_subitem: :ec_graduation_requirement) + .includes(:ec_course_target, ec_graduation_subitem: :ec_graduation_requirement) subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr| subitem = arr.first.ec_graduation_subitem @@ -37,7 +37,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService arr.map(&:ec_course_target).uniq.each do |target| target_total_rates += target.weight.to_f - student_score = student_score_map[target.id] + student_score = student_score_map[target.id]&.first reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score end @@ -60,8 +60,19 @@ class Ecs::QueryCourseEvaluationService < ApplicationService def score_levels_map @_score_levels_map ||= begin + index = 0 ec_course.ec_score_levels.each_with_object({}) do |level, obj| - obj[level.id.to_s] = level.as_json(only: %i[id position score level]) + hash = level.as_json(only: %i[id position score level]) + + hash[:description] = + case index + when 0 then "#{level.score}分以上" + when ec_course.ec_score_levels.to_a.size - 1 then "低于#{level.score}分" + else "#{level.score}~#{ec_course.ec_score_levels[index - 1].score - 1}分" + end + + index += 1 + obj[level.id.to_s] = hash end end end @@ -87,23 +98,29 @@ class Ecs::QueryCourseEvaluationService < ApplicationService @_course_achievement += data[:average_score].to_f * course_target.weight.to_f # 计算学生成绩分布区间 + student_count = 0 data[:score_levels] = score_levels.map do |score_level| level_condition_proc = if (score_level.position - 1).zero? # 第一区间 -> (score_target){ score_target.score >= score_level.score ? 1 : 0 } - elsif score_levels.position == score_levels.size # 末尾区间 + elsif score_level.position == score_levels.size # 末尾区间 -> (score_target){ score_target.score < score_level.score ? 1 : 0 } else # 中间区间 - -> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 } + -> (score_target){ score_target.score >= score_level.score && score_target.score < score_levels[score_level.position - 1].score ? 1 : 0 } end # 计算该成绩区间人数 count = score_targets.sum(&level_condition_proc) + student_count += count { id: score_level.id, count: count } end + data[:score_levels].each do |score_level| + score_level[:rate] = score_level[:count].fdiv(student_count).round(2) + end + data end end diff --git a/app/services/ecs/save_graduation_course_supports_service.rb b/app/services/ecs/save_graduation_course_supports_service.rb index bfbdb997f..de4ecc71a 100644 --- a/app/services/ecs/save_graduation_course_supports_service.rb +++ b/app/services/ecs/save_graduation_course_supports_service.rb @@ -9,6 +9,8 @@ class Ecs::SaveGraduationCourseSupportsService < ApplicationService end def call + set_course_supports_position! + Ecs::SaveGraduationCourseSupportForm.new(params).validate! accepts_attributes = build_accepts_nested_attributes( @@ -20,4 +22,10 @@ class Ecs::SaveGraduationCourseSupportsService < ApplicationService graduation_subitem.save! graduation_subitem end + + def set_course_supports_position! + params[:course_supports].each_with_index do |item, index| + item[:position] = index + 1 + end + end end \ No newline at end of file diff --git a/app/services/users/apply_professional_auth_service.rb b/app/services/users/apply_professional_auth_service.rb index 3ba9fbafd..74ee08c85 100644 --- a/app/services/users/apply_professional_auth_service.rb +++ b/app/services/users/apply_professional_auth_service.rb @@ -40,8 +40,8 @@ class Users::ApplyProfessionalAuthService < ApplicationService # sms_cache = Rails.cache.read("apply_pro_certification") # if sms_cache.nil? - # sms_notify_admin - Rails.cache.write("apply_pro_certification", 1) + sms_notify_admin + # Rails.cache.write("apply_pro_certification", 1) # end end end diff --git a/app/tasks/statistic_school_daily_report_task.rb b/app/tasks/statistic_school_daily_report_task.rb index 5cd3fda7c..794a4b573 100644 --- a/app/tasks/statistic_school_daily_report_task.rb +++ b/app/tasks/statistic_school_daily_report_task.rb @@ -27,8 +27,8 @@ class StatisticSchoolDailyReportTask # 新增实训评测数量 shixun_evaluate_count = EvaluateRecord.joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = evaluate_records.shixun_id') .joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4') - .joins('LEFT JOIN members ON members.user_id = evaluate_records.user_id') - .joins('LEFT JOIN courses ON members.course_id = courses.id AND hc.course_id = courses.id') + .joins('LEFT JOIN course_members ON course_members.user_id = evaluate_records.user_id') + .joins('LEFT JOIN courses ON course_members.course_id = courses.id AND hc.course_id = courses.id') .where(courses: { school_id: school.id }) .where(created_at: yesterday).reorder(nil).count diff --git a/app/tasks/statistic_school_report_task.rb b/app/tasks/statistic_school_report_task.rb index a55eb7a42..a72c57830 100644 --- a/app/tasks/statistic_school_report_task.rb +++ b/app/tasks/statistic_school_report_task.rb @@ -2,10 +2,10 @@ class StatisticSchoolReportTask def call School.find_each do |school| evaluate_count = Game.joins(:challenge) - .joins('LEFT JOIN members ON members.user_id = games.user_id') + .joins('LEFT JOIN course_members ON course_members.user_id = games.user_id') .joins('LEFT JOIN homework_commons_shixuns hcs ON hcs.shixun_id = challenges.shixun_id') .joins('LEFT JOIN homework_commons hc ON hcs.homework_common_id = hc.id AND hc.homework_type = 4') - .joins('LEFT JOIN courses ON hc.course_id = courses.id AND members.course_id = courses.id') + .joins('LEFT JOIN courses ON hc.course_id = courses.id AND course_members.course_id = courses.id') .where(courses: { school_id: school.id }) .sum(:evaluate_count) diff --git a/app/views/admins/schools/index.html.erb b/app/views/admins/schools/index.html.erb new file mode 100644 index 000000000..0dd5b0bc5 --- /dev/null +++ b/app/views/admins/schools/index.html.erb @@ -0,0 +1,16 @@ +<% define_admin_breadcrumbs do %> + <% add_admin_breadcrumb('单位列表') %> +<% end %> + +
+ <%= form_tag(admins_schools_path, method: :get, class: 'form-inline search-form flex-1', remote: true) do %> + <%= text_field_tag(:keyword, params[:keyword], class: 'form-control col-sm-2 ml-3', placeholder: '部门名称检索') %> + <%= submit_tag('搜索', class: 'btn btn-primary ml-3', 'data-disable-with': '搜索中...') %> + <% end %> + + <%#= javascript_void_link '新建单位', class: 'btn btn-primary', data: { toggle: 'modal', target: '.admin-create-school-modal' } %> +
+ +
+ <%= render partial: 'admins/schools/shared/list', locals: { schools: @schools } %> +
\ No newline at end of file diff --git a/app/views/admins/schools/index.js.erb b/app/views/admins/schools/index.js.erb new file mode 100644 index 000000000..41a2454be --- /dev/null +++ b/app/views/admins/schools/index.js.erb @@ -0,0 +1 @@ +$('.school-list-container').html("<%= j(render partial: 'admins/schools/shared/list', locals: { schools: @schools }) %>"); \ No newline at end of file diff --git a/app/views/admins/schools/shared/_list.html.erb b/app/views/admins/schools/shared/_list.html.erb new file mode 100644 index 000000000..74df29cee --- /dev/null +++ b/app/views/admins/schools/shared/_list.html.erb @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + <% if schools.present? %> + <% schools.each do |school| %> + + + + + + + + + + + + + + <% end %> + <% else %> + <%= render 'admins/shared/no_data_for_table' %> + <% end %> + +
IDLOGO标识码单位名称地区城市详细地址<%= sort_tag('用户数', name: 'users_count', path: admins_schools_path) %>部门数<%= sort_tag('创建时间', name: 'created_at', path: admins_schools_path) %>操作
<%= school.id %> + <% if Util::FileManage.exists?(school) %> + <%= image_tag(Util::FileManage.source_disk_file_url(school).to_s + "?#{Time.now.to_i}", width: 40, height: 40, class: 'preview-image') %> + <% else %> + <%= content_tag(:span, '--', class: 'text-secondary') %> + <% end %> + <%= display_text school.identifier %><%= school.name %><%= school.province %><%= school.city %><%= school.address %><%= school.users_count %><%= @department_count.fetch(school.id, 0) %><%= school.created_at&.strftime('%Y-%m-%d %H:%M') %> + <%= delete_link '删除', admins_school_path(school, element: ".school-item-#{school.id}"), class: 'delete-school-action' %> +
+ +<%= render partial: 'admins/shared/paginate', locals: { objects: schools } %> \ No newline at end of file diff --git a/app/views/admins/shared/_sidebar.html.erb b/app/views/admins/shared/_sidebar.html.erb index da65099ca..2d9461f45 100644 --- a/app/views/admins/shared/_sidebar.html.erb +++ b/app/views/admins/shared/_sidebar.html.erb @@ -31,6 +31,7 @@
  • <%= sidebar_item_group('#schools-submenu', '单位管理', icon: 'building') do %> +
  • <%= sidebar_item(admins_schools_path, '单位列表', icon: 'university', controller: 'admins-schools') %>
  • <%= sidebar_item(admins_departments_path, '部门列表', icon: 'sitemap', controller: 'admins-departments') %>
  • <% end %> diff --git a/app/views/admins/users/index.html.erb b/app/views/admins/users/index.html.erb index 0892b5641..4b8307a7a 100644 --- a/app/views/admins/users/index.html.erb +++ b/app/views/admins/users/index.html.erb @@ -12,7 +12,7 @@
    - <% identity_options = [['全部', '']] + UserExtension.identities.map { |k, v| [I18n.t("user.identity.#{k}"), v] } %> + <% identity_options = [['全部', ''], ['教师', 0], ['学生', 1], ['专业人士', 2]] %> <%= select_tag(:identity, options_for_select(identity_options), class: 'form-control') %>
    diff --git a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx index 900ff5888..934e1c4be 100644 --- a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx +++ b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx @@ -13,7 +13,7 @@ wb.styles do |style| name = course_evaluation.name items_size = course_evaluation.ec_course_evaluation_subitems.count - sheet.add_row name, style: bg_style + sheet.add_row [name], style: bg_style sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))] data = [] diff --git a/app/views/ecs/course_evaluations/index.json.jbuilder b/app/views/ecs/course_evaluations/index.json.jbuilder index e1c63d44d..b120bccc2 100644 --- a/app/views/ecs/course_evaluations/index.json.jbuilder +++ b/app/views/ecs/course_evaluations/index.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation', as: :ec_course_evaluation diff --git a/app/views/ecs/course_evaluations/show.json.jbuilder b/app/views/ecs/course_evaluations/show.json.jbuilder index b03ddc076..f67053183 100644 --- a/app/views/ecs/course_evaluations/show.json.jbuilder +++ b/app/views/ecs/course_evaluations/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation +json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation diff --git a/app/views/ecs/course_evaluations/slimmer.json.jbuilder b/app/views/ecs/course_evaluations/slimmer.json.jbuilder index 929cfe7be..6e0faef3e 100644 --- a/app/views/ecs/course_evaluations/slimmer.json.jbuilder +++ b/app/views/ecs/course_evaluations/slimmer.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation_slim', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation diff --git a/app/views/ecs/course_targets/index.json.jbuilder b/app/views/ecs/course_targets/index.json.jbuilder index 6590ecc10..9ec4af823 100644 --- a/app/views/ecs/course_targets/index.json.jbuilder +++ b/app/views/ecs/course_targets/index.json.jbuilder @@ -1,2 +1,2 @@ -json.course_targets @course_targets, partial: 'shared/course_target', as: :ec_course_target +json.course_targets @course_targets, partial: 'ecs/course_targets/shared/course_target', as: :ec_course_target diff --git a/app/views/ecs/course_targets/index.xlsx.axlsx b/app/views/ecs/course_targets/index.xlsx.axlsx index a188ad95c..ef4215b03 100644 --- a/app/views/ecs/course_targets/index.xlsx.axlsx +++ b/app/views/ecs/course_targets/index.xlsx.axlsx @@ -15,7 +15,7 @@ wb.styles do |style| name = "#{@_current_course.name}课程目标" wb.add_worksheet(name: name) do |sheet| - sheet.add_row name, style: title_style + sheet.add_row [name], style: title_style sheet.add_row [] sheet.add_row [] diff --git a/app/views/ecs/ec_courses/search.json.jbuilder b/app/views/ecs/ec_courses/search.json.jbuilder index fc22586d7..cf00a2b98 100644 --- a/app/views/ecs/ec_courses/search.json.jbuilder +++ b/app/views/ecs/ec_courses/search.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.ec_courses @ec_courses, partial: 'shared/ec_course_slim', as: :ec_course \ No newline at end of file +json.ec_courses @ec_courses, partial: 'ecs/ec_courses/shared/ec_course_slim', as: :ec_course \ No newline at end of file diff --git a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder index 6fbbf249b..ffb83ed23 100644 --- a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder @@ -1,3 +1,3 @@ json.count @graduation_requirements.size -json.graduation_requirements @graduation_requirements, partial: 'shared/ec_graduation_requirement', as: :ec_graduation_requirement +json.graduation_requirements @graduation_requirements, partial: '/ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement diff --git a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx index aeb802329..9a2081861 100644 --- a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx +++ b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx @@ -6,15 +6,15 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求及指标点') do |sheet| - sheet.add_row '毕业要求及指标点', style: title_style + sheet.add_row ['毕业要求及指标点'], style: title_style sheet.add_row [] - sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业代码', major.code.to_s + ' '], style: ec_year_style sheet.add_row ['专业名称', major.name], style: ec_year_style sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style @@ -32,12 +32,15 @@ wb.styles do |style| end items_size = requirement.ec_graduation_subitems.size - sheet.merge_cells("A#{index}:A#{index + items_size}") - sheet.merge_cells("B#{index}:B#{index + items_size}") + if items_size.zero? + sheet.add_row [requirement_content, ''], style: content_style + else + sheet.merge_cells("A#{index + 1}:A#{index + items_size}") + end index += items_size end - sheet.column_widths [400, 400] + sheet.column_widths 100, 100 end end \ No newline at end of file diff --git a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder index 562c255a9..d3a8db1fc 100644 --- a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder @@ -1,2 +1,2 @@ -json.partial! 'shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement +json.partial! 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement diff --git a/app/views/ecs/ec_major_schools/index.json.jbuilder b/app/views/ecs/ec_major_schools/index.json.jbuilder index 0924b71ea..312abd26b 100644 --- a/app/views/ecs/ec_major_schools/index.json.jbuilder +++ b/app/views/ecs/ec_major_schools/index.json.jbuilder @@ -3,7 +3,7 @@ json.count @count # 示例专业 json.template_ec_major_school do - json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school + json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school if @template_major_school end # 专业 @@ -11,5 +11,5 @@ json.ec_major_schools @major_schools do |ec_major_school| json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school # 专业管理员 - json.major_managers ec_major_school.users, partial: 'ecs/ec_major_schools/shared/ec_major_school', as: :user + json.major_managers ec_major_school.users, partial: 'users/user_simple', as: :user end diff --git a/app/views/ecs/ec_major_schools/show.json.jbuilder b/app/views/ecs/ec_major_schools/show.json.jbuilder new file mode 100644 index 000000000..7c911d824 --- /dev/null +++ b/app/views/ecs/ec_major_schools/show.json.jbuilder @@ -0,0 +1,6 @@ +json.extract! @major, :id, :code, :name, :template_major +json.school_id @major.school.id +json.school_name @major.school.name + +can_manager = @major.manager?(current_user) || @major.school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/app/views/ecs/ec_majors/index.json.jbuilder b/app/views/ecs/ec_majors/index.json.jbuilder index 34ee9a907..df3373fed 100644 --- a/app/views/ecs/ec_majors/index.json.jbuilder +++ b/app/views/ecs/ec_majors/index.json.jbuilder @@ -1,2 +1,7 @@ json.count @count -json.es_majors @ec_majors, partial: 'ecs/majors/shared/ec_major', as: :ec_major +json.ec_majors do + json.array! @ec_majors.each do |major| + json.extract! major, :id, :name, :code + json.selected @major_ids.include?(major.id) + end +end diff --git a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder index 83414d2f4..61992d8e1 100644 --- a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder @@ -1,3 +1,3 @@ json.extract! ec_training_objective, :id, :content -json.ec_training_items ec_training_objective.ec_training_subitems, partial: 'ec_training_subitem', as: :ec_training_subitem +json.ec_training_items ec_training_objective.ec_training_subitems, partial: '/ecs/ec_training_objectives/shared/ec_training_subitem', as: :ec_training_subitem diff --git a/app/views/ecs/ec_training_objectives/show.json.jbuilder b/app/views/ecs/ec_training_objectives/show.json.jbuilder index a37fa1c09..00825be4c 100644 --- a/app/views/ecs/ec_training_objectives/show.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_training_objective', ec_training_objective: @training_objective +json.partial! '/ecs/ec_training_objectives/shared/ec_training_objective', ec_training_objective: @training_objective diff --git a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx index 4746be0ea..130e80e6b 100644 --- a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx +++ b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx @@ -6,11 +6,11 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', border: { style: :thin, color: '000000' }, alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '培养目标及目标分解') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['培养目标及目标分解'], style: title_style sheet.add_row [] sheet.add_row [] @@ -27,6 +27,6 @@ wb.styles do |style| end items_size = training_objective.ec_training_subitems.size - sheet.merge_cells("A9:A#{9 + items_size}") + sheet.merge_cells("A9:A#{9 + items_size - 1}") end end \ No newline at end of file diff --git a/app/views/ecs/ec_years/index.json.jbuilder b/app/views/ecs/ec_years/index.json.jbuilder index c5c89cd06..b0a8985b2 100644 --- a/app/views/ecs/ec_years/index.json.jbuilder +++ b/app/views/ecs/ec_years/index.json.jbuilder @@ -8,7 +8,16 @@ json.ec_years do json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0) json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0) json.course_count @course_count_map.fetch(ec_year.id, 0) - json.course_target_count @course_target_count_map.fetch(ec_year.id, 0) - json.graduation_subitem_count @graduation_subitem_count_map.fetch(ec_year.id, 0) + + course_target = @course_target_count_map.fetch(ec_year.id, 0) + graduation_subitem = @graduation_subitem_count_map.fetch(ec_year.id, 0) + achieved_course = achieved_graduation_course_count(ec_year) + achieved_objective = achieved_graduation_objective_count(ec_year) + + json.course_target_count course_target + json.graduation_subitem_count graduation_subitem + json.achieved_graduation_course_count achieved_course + json.achieved_graduation_objective_count achieved_objective + json.status graduation_subitem == achieved_objective ? 'achieved' : 'not_achieved' end end \ No newline at end of file diff --git a/app/views/ecs/ec_years/show.json.jbuilder b/app/views/ecs/ec_years/show.json.jbuilder new file mode 100644 index 000000000..ba8333086 --- /dev/null +++ b/app/views/ecs/ec_years/show.json.jbuilder @@ -0,0 +1,13 @@ +json.extract! @year, :id, :year + +major = @year.ec_major_school +json.major_id major.id +json.major_name major.name +json.major_code major.code + +school = major.school +json.school_id school.id +json.school_name school.name + +can_manager = major.manager?(current_user) || school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/app/views/ecs/graduation_course_supports/create.json.jbuilder b/app/views/ecs/graduation_course_supports/create.json.jbuilder index c05024911..d8749a5dc 100644 --- a/app/views/ecs/graduation_course_supports/create.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/create.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem +json.partial! 'ecs/graduation_course_supports/shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem diff --git a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder index 1ffe12ec4..ced8a5c72 100644 --- a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder @@ -2,4 +2,5 @@ json.extract! ec_graduation_subitem, :id, :position, :content, :ec_graduation_re json.graduation_requirement_position ec_graduation_subitem.ec_graduation_requirement.position -json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ec_course_support', as: :ec_course_support +json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ecs/graduation_course_supports/shared/ec_course_support', as: :ec_course_support +json.weights_total ec_graduation_subitem.ec_course_supports.to_a.sum(&:weights) diff --git a/app/views/ecs/graduation_course_supports/show.json.jbuilder b/app/views/ecs/graduation_course_supports/show.json.jbuilder index a9e4bdc22..495f9c6a9 100644 --- a/app/views/ecs/graduation_course_supports/show.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/show.json.jbuilder @@ -1,3 +1,3 @@ json.course_count @course_count -json.graduation_subitems @graduation_subitems, partial: 'shared/ec_graduation_subitem', as: :ec_graduation_subitem +json.graduation_subitems @graduation_subitems, partial: 'ecs/graduation_course_supports/shared/ec_graduation_subitem', as: :ec_graduation_subitem json.count @graduation_subitems.size diff --git a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx index fd1a44935..e2c2599ec 100644 --- a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx +++ b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx @@ -14,7 +14,7 @@ wb.styles do |style| tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A') wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet| - sheet.add_row '课程体系VS毕业要求', style: title_style + sheet.add_row ['课程体系VS毕业要求'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))] sheet.add_row [] diff --git a/app/views/ecs/graduation_subitems/index.json.jbuilder b/app/views/ecs/graduation_subitems/index.json.jbuilder new file mode 100644 index 000000000..0a1235b1d --- /dev/null +++ b/app/views/ecs/graduation_subitems/index.json.jbuilder @@ -0,0 +1,8 @@ +json.graduation_subitems do + json.array! @graduation_subitems do |graduation_subitem| + json.extract! graduation_subitem, :id, :position, :content + json.graduation_requirement_position graduation_subitem.ec_graduation_requirement.position + end +end + +json.count @graduation_subitems.size \ No newline at end of file diff --git a/app/views/ecs/homes/index.json.jbuilder b/app/views/ecs/homes/index.json.jbuilder index 9bf21f056..8546f6c4a 100644 --- a/app/views/ecs/homes/index.json.jbuilder +++ b/app/views/ecs/homes/index.json.jbuilder @@ -13,4 +13,4 @@ json.school do json.name current_school.name end -json.school_managers @school_managers, partial: 'ecs/shared/user', as: :user +json.school_managers @school_managers, partial: 'users/user_simple', as: :user diff --git a/app/views/ecs/major_managers/create.json.jbuilder b/app/views/ecs/major_managers/create.json.jbuilder deleted file mode 100644 index ff7ff01e5..000000000 --- a/app/views/ecs/major_managers/create.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/reach_evaluations/show.xlsx.axlsx b/app/views/ecs/reach_evaluations/show.xlsx.axlsx index a62e4f6c2..a79d059a3 100644 --- a/app/views/ecs/reach_evaluations/show.xlsx.axlsx +++ b/app/views/ecs/reach_evaluations/show.xlsx.axlsx @@ -10,7 +10,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['达成度-毕业要求综合评价报表'], style: title_style sheet.merge_cells("A1:D1") sheet.add_row [] diff --git a/app/views/ecs/requirement_support_objectives/show.json.jbuilder b/app/views/ecs/requirement_support_objectives/show.json.jbuilder index 1ba783304..642a5f10c 100644 --- a/app/views/ecs/requirement_support_objectives/show.json.jbuilder +++ b/app/views/ecs/requirement_support_objectives/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem -json.requirement_support_objectives @requirement_support_objectives, partial: 'shared/requirement_support_objective', as: :requirement_support_objective +json.requirement_support_objectives @requirement_support_objectives, partial: 'ecs/requirement_support_objectives/shared/requirement_support_objective', as: :requirement_support_objective diff --git a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx index 934ad2941..6534ce36a 100644 --- a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx +++ b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx @@ -16,7 +16,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet| - sheet.add_row '毕业要求 vs 培养目标矩阵', style: title_style + sheet.add_row ['毕业要求 vs 培养目标矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..subitem_size)] diff --git a/app/views/ecs/score_levels/show.json.jbuilder b/app/views/ecs/score_levels/show.json.jbuilder index 0c8b76d86..dcdf63cdc 100644 --- a/app/views/ecs/score_levels/show.json.jbuilder +++ b/app/views/ecs/score_levels/show.json.jbuilder @@ -1 +1 @@ -json.score_levels @score_levels, partial: 'shared/ec_score_level', as: :ec_score_level +json.score_levels @score_levels, partial: 'ecs/score_levels/shared/ec_score_level', as: :ec_score_level diff --git a/app/views/ecs/students/show.json.jbuilder b/app/views/ecs/students/show.json.jbuilder index 352970055..468a1cfe3 100644 --- a/app/views/ecs/students/show.json.jbuilder +++ b/app/views/ecs/students/show.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.students @students, partial: 'shared/ec_year_student', as: :ec_year_student \ No newline at end of file +json.students @students, partial: 'ecs/students/shared/ec_year_student', as: :ec_year_student \ No newline at end of file diff --git a/app/views/ecs/subitem_support_standards/show.json.jbuilder b/app/views/ecs/subitem_support_standards/show.json.jbuilder index 94fd6c5a0..a92fe7000 100644 --- a/app/views/ecs/subitem_support_standards/show.json.jbuilder +++ b/app/views/ecs/subitem_support_standards/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem -json.subitem_support_standards @subitem_support_standards, partial: 'shared/subitem_support_standard', as: :subitem_support_standard +json.subitem_support_standards @subitem_support_standards, partial: 'ecs/subitem_support_standards/shared/subitem_support_standard', as: :subitem_support_standard diff --git a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx index e12f517f3..8329a27ee 100644 --- a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx +++ b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx @@ -17,7 +17,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet| - sheet.add_row '毕业要求 vs 通用标准矩阵', style: title_style + sheet.add_row ['毕业要求 vs 通用标准矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..standards_size)] diff --git a/app/views/ecs/users/index.json.jbuilder b/app/views/ecs/users/index.json.jbuilder new file mode 100644 index 000000000..0109b9ca0 --- /dev/null +++ b/app/views/ecs/users/index.json.jbuilder @@ -0,0 +1,12 @@ +json.count @count +json.users do + json.array! @users.each do |user| + json.id user.id + json.name user.real_name + json.identity user.identity + json.school_name user.school_name + json.department_name user.department_name + json.phone Util.conceal(user.phone, :phone) + json.manager @manager_ids.include?(user.id) + end +end \ No newline at end of file diff --git a/app/views/student_works/show.json.jbuilder b/app/views/student_works/show.json.jbuilder index 192e4d8ec..9bafbe93e 100644 --- a/app/views/student_works/show.json.jbuilder +++ b/app/views/student_works/show.json.jbuilder @@ -11,7 +11,7 @@ json.update_user_name @is_evaluation ? "匿名" : @work.update_user.try(:real_na json.update_atta @homework.late_duration && @is_author json.attachments @attachments do |atta| - json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: @work.delete_atta(atta)} + json.partial! "attachments/attachment_simple", locals: {attachment: atta, delete: false} end unless @is_evaluation diff --git a/app/views/tidings/_tiding.json.jbuilder b/app/views/tidings/_tiding.json.jbuilder index 959a96ebd..b53574274 100644 --- a/app/views/tidings/_tiding.json.jbuilder +++ b/app/views/tidings/_tiding.json.jbuilder @@ -17,8 +17,11 @@ json.homework_type homework_type json.time tiding.how_long_time json.new_tiding tiding.unread?(@onclick_time) +# 需要系统头像 +show_system_user = tiding.trigger_user_id.zero? || tiding.tiding_type == 'System' || tiding.anonymous? + json.trigger_user do - if tiding.trigger_user_id.zero? || (tiding.trigger_user_id == 1 && tiding.tiding_type == 'System') + if show_system_user json.id 0 json.name "系统" json.login "" diff --git a/config/locales/tidings/zh-CN.yml b/config/locales/tidings/zh-CN.yml index e6e8e676d..ce6fd57b0 100644 --- a/config/locales/tidings/zh-CN.yml +++ b/config/locales/tidings/zh-CN.yml @@ -19,7 +19,7 @@ "9_2_end": "你提交的加入课堂申请:%s(教师), 审核未通过" "7_1_end": "你提交的加入课堂申请:%s(助教), 审核已通过" "7_2_end": "你提交的加入课堂申请:%s(助教), 审核未通过" - StudentJoinCourse_end: "加入了课堂:%s(学生)" + StudentJoinCourse_end: "%s 加入了课堂:%s(学生)" TeacherJoinCourse: "2_end": "%s将你加入课堂:%s(教师)" "3_end": "%s将你加入课堂:%s(助教)" @@ -202,6 +202,7 @@ 2_end: "别人对你的匿评发起的申诉申请:%s,审核未通过" StudentWork: Apply_end: "发起了匿评申诉申请:%s" + HomeworkCommon_end: "发起了匿评申诉申请:%s" System_end: "有人对你的匿评发起了申诉:%s" Department_end: "你选填的二级单位:%s(%s)因不符合规范,已被系统删除.请重新选择" Library: diff --git a/config/locales/users/zh-CN.yml b/config/locales/users/zh-CN.yml index 48b8ca075..dc49b6617 100644 --- a/config/locales/users/zh-CN.yml +++ b/config/locales/users/zh-CN.yml @@ -13,7 +13,9 @@ professional: 专业人士 developer: 从业者 enterprise: 组织 + unselect: 未选择 "0": 教师 "1": 学生 "2": 专业人士 - "3": 专业人士 \ No newline at end of file + "3": 从业者 + "4": 组织 \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index ba851b2f2..1647101ea 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -710,14 +710,15 @@ Rails.application.routes.draw do # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 scope module: :ecs do - resources :ec_major_schools, only: [] do + resources :ec_major_schools, only: [:show] do + resources :users, only: [:index] resources :major_managers, only: [:create, :destroy] - resources :ec_years, only: [:index, :create, :destroy] + resources :ec_years, only: [:index, :show, :create, :destroy] end resources :ec_years, only: [] do resource :ec_training_objectives, only: [:show, :create] - resources :ec_graduation_requirements, only: [:index, :create] + resources :ec_graduation_requirements, only: [:index, :create, :update, :destroy] resource :requirement_support_objectives, only: [:show, :create, :destroy] resource :subitem_support_standards, only: [:show, :create, :destroy] resource :students, only: [:show, :destroy] do @@ -736,6 +737,7 @@ Rails.application.routes.draw do resource :graduation_course_supports, only: [:show, :create] resource :reach_evaluation, only: [:show, :create] resource :reach_criteria, only: [:create] + resources :graduation_subitems, only: [:index] end resources :ec_courses, only: [] do @@ -926,6 +928,7 @@ Rails.application.routes.draw do resources :mirror_scripts, only: [:index, :new, :create, :edit, :update, :destroy] end resources :choose_mirror_repositories, only: [:new, :create] + resources :schools, only: [:index, :destroy] resources :departments, only: [:index, :create, :edit, :update, :destroy] do resource :department_member, only: [:create, :update, :destroy] post :merge, on: :collection diff --git a/db/migrate/20190911080150_change_ec_course_supports.rb b/db/migrate/20190911080150_change_ec_course_supports.rb new file mode 100644 index 000000000..07c3a536d --- /dev/null +++ b/db/migrate/20190911080150_change_ec_course_supports.rb @@ -0,0 +1,11 @@ +class ChangeEcCourseSupports < ActiveRecord::Migration[5.2] + def change + add_column :ec_course_supports, :ec_graduation_subitem_id, :integer, index: true + + execute <<-SQL + UPDATE ec_course_supports ecs SET ec_graduation_subitem_id = ( + SELECT ec_graduation_subitem_id FROM ec_graduation_subitem_courses egsc WHERE egsc.ec_course_support_id = ecs.id + ) + SQL + end +end diff --git a/db/migrate/20190920073337_migrate_user_extension_index.rb b/db/migrate/20190920073337_migrate_user_extension_index.rb new file mode 100644 index 000000000..1d333bd99 --- /dev/null +++ b/db/migrate/20190920073337_migrate_user_extension_index.rb @@ -0,0 +1,6 @@ +class MigrateUserExtensionIndex < ActiveRecord::Migration[5.2] + def change + remove_index :user_extensions, :school_id + add_index :user_extensions, [:school_id, :user_id] + end +end diff --git a/lib/tasks/public_course_sync.rake b/lib/tasks/public_course_sync.rake index a22a9f1f8..c26090e81 100644 --- a/lib/tasks/public_course_sync.rake +++ b/lib/tasks/public_course_sync.rake @@ -81,8 +81,10 @@ namespace :public_classes do homework.update_columns(publish_time: publish_time, end_time: end_time, created_at: created_at, updated_at: updated_at) homework.homework_detail_manual.update_columns(comment_status: 6, created_at: created_at, updated_at: updated_at) + homework.update_homework_work_score + homework.update_attribute('calculation_time', end_time) - homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) + # homework.student_works.where("work_status !=0 and update_time > '#{end_time}'").update_all(update_time: end_time) end when 3 # 试卷 diff --git a/public/editormd/lib/marked.min.js b/public/editormd/lib/marked.min.js index 4db085adb..1cd7c2bae 100644 --- a/public/editormd/lib/marked.min.js +++ b/public/editormd/lib/marked.min.js @@ -10,7 +10,9 @@ out+=this.renderer.em(this.output(cap[2]||cap[1])) --> out+=this.renderer.em(this.output(cap[2]||cap[1]), cap.input) */ -(function(){var block={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:noop,hr:/^( *[-*_]){3,} *(?:\n+|$)/,heading:/^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,nptable:noop,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,blockquote:/^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:/^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,def:/^ *\[([^\]]+)\]: *]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,table:noop,paragraph:/^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,text:/^[^\n]+/};block.bullet=/(?:[*+-]|\d+\.)/;block.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;block.item=replace(block.item,"gm")(/bull/g,block.bullet)();block.list=replace(block.list)(/bull/g,block.bullet)("hr","\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))")("def","\\n+(?="+block.def.source+")")();block.blockquote=replace(block.blockquote)("def",block.def)();block._tag="(?!(?:"+"a|em|strong|small|s|cite|q|dfn|abbr|data|time|code"+"|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo"+"|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b";block.html=replace(block.html)("comment",//)("closed",/<(tag)[\s\S]+?<\/\1>/)("closing",/])*?>/)(/tag/g,block._tag)();block.paragraph=replace(block.paragraph)("hr",block.hr)("heading",block.heading)("lheading",block.lheading)("blockquote",block.blockquote)("tag","<"+block._tag)("def",block.def)();block.normal=merge({},block);block.gfm=merge({},block.normal,{fences:/^ *(`{3,}|~{3,}) *(\S+)? *\n([\s\S]+?)\s*\1 *(?:\n+|$)/,paragraph:/^/});block.gfm.paragraph=replace(block.paragraph)("(?!","(?!"+block.gfm.fences.source.replace("\\1","\\2")+"|"+block.list.source.replace("\\1","\\3")+"|")();block.tables=merge({},block.gfm,{nptable:/^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,table:/^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/});function Lexer(options){this.tokens=[];this.tokens.links={};this.options=options||marked.defaults;this.rules=block.normal;if(this.options.gfm){if(this.options.tables){this.rules=block.tables}else{this.rules=block.gfm}}}Lexer.rules=block;Lexer.lex=function(src,options){var lexer=new Lexer(options);return lexer.lex(src)};Lexer.prototype.lex=function(src){src=src.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n");return this.token(src,true)};Lexer.prototype.token=function(src,top,bq){var src=src.replace(/^ +$/gm,""),next,loose,cap,bull,b,item,space,i,l;while(src){if(cap=this.rules.newline.exec(src)){src=src.substring(cap[0].length);if(cap[0].length>1){this.tokens.push({type:"space"})}}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);cap=cap[0].replace(/^ {4}/gm,"");this.tokens.push({type:"code",text:!this.options.pedantic?cap.replace(/\n+$/,""):cap});continue}if(cap=this.rules.fences.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"code",lang:cap[2],text:cap[3]});continue}if(cap=this.rules.heading.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:"heading",depth:cap[1].length,text:cap[2]});continue}if(top&&(cap=this.rules.nptable.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/\n$/,"").split("\n")};for(i=0;i ?/gm,"");this.token(cap,top,true);this.tokens.push({type:"blockquote_end"});continue}if(cap=this.rules.list.exec(src)){src=src.substring(cap[0].length);bull=cap[2];this.tokens.push({type:"list_start",ordered:bull.length>1});cap=cap[0].match(this.rules.item);next=false;l=cap.length;i=0;for(;i1&&b.length>1)){src=cap.slice(i+1).join("\n")+src;i=l-1}}loose=next||/\n\n(?!\s*$)/.test(item);if(i!==l-1){next=item.charAt(item.length-1)==="\n";if(!loose){loose=next}}this.tokens.push({type:loose?"loose_item_start":"list_item_start"});this.token(item,false,bq); -this.tokens.push({type:"list_item_end"})}this.tokens.push({type:"list_end"});continue}if(cap=this.rules.html.exec(src)){src=src.substring(cap[0].length);this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:cap[1]==="pre"||cap[1]==="script"||cap[1]==="style",text:cap[0]});continue}if((!bq&&top)&&(cap=this.rules.def.exec(src))){src=src.substring(cap[0].length);this.tokens.links[cap[1].toLowerCase()]={href:cap[2],title:cap[3]};continue}if(top&&(cap=this.rules.table.exec(src))){src=src.substring(cap[0].length);item={type:"table",header:cap[1].replace(/^ *| *\| *$/g,"").split(/ *\| */),align:cap[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:cap[3].replace(/(?: *\| *)?\n$/,"").split("\n")};for(i=0;i])/,autolink:/^<([^ >]+(@|:\/)[^ >]+)>/,url:noop,tag:/^|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,link:/^!?\[(inside)\]\(href\)/,reflink:/^!?\[(inside)\]\s*\[([^\]]*)\]/,nolink:/^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,strong:/^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,em:/^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:noop,text:/^[\s\S]+?(?=[\\?(?:\s+['"]([\s\S]*?)['"])?\s*/;inline.link=replace(inline.link)("inside",inline._inside)("href",inline._href)();inline.reflink=replace(inline.reflink)("inside",inline._inside)();inline.normal=merge({},inline);inline.pedantic=merge({},inline.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/});inline.gfm=merge({},inline.normal,{escape:replace(inline.escape)("])","~|])")(),url:/^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:replace(inline.text)("]|","~]|")("|","|https?://|")()});inline.breaks=merge({},inline.gfm,{br:replace(inline.br)("{2,}","*")(),text:replace(inline.gfm.text)("{2,}","*")()});function InlineLexer(links,options){this.options=options||marked.defaults;this.links=links;this.rules=inline.normal;this.renderer=this.options.renderer||new Renderer;this.renderer.options=this.options;if(!this.links){throw new Error("Tokens array requires a `links` property.")}if(this.options.gfm){if(this.options.breaks){this.rules=inline.breaks}else{this.rules=inline.gfm}}else{if(this.options.pedantic){this.rules=inline.pedantic}}}InlineLexer.rules=inline;InlineLexer.output=function(src,links,options){var inline=new InlineLexer(links,options);return inline.output(src)};InlineLexer.prototype.output=function(src){var out="",link,text,href,cap;while(src){if(cap=this.rules.escape.exec(src)){src=src.substring(cap[0].length);out+=cap[1];continue}if(cap=this.rules.autolink.exec(src)){src=src.substring(cap[0].length);if(cap[2]==="@"){text=cap[1].charAt(6)===":"?this.mangle(cap[1].substring(7)):this.mangle(cap[1]);href=this.mangle("mailto:")+text}else{text=escape(cap[1]);href=text}out+=this.renderer.link(href,null,text);continue}if(!this.inLink&&(cap=this.rules.url.exec(src))){src=src.substring(cap[0].length);text=escape(cap[1]);href=text;out+=this.renderer.link(href,null,text);continue}if(cap=this.rules.tag.exec(src)){if(!this.inLink&&/^/i.test(cap[0])){this.inLink=false}}src=src.substring(cap[0].length);out+=this.options.sanitize?escape(cap[0]):cap[0];continue}if(cap=this.rules.link.exec(src)){src=src.substring(cap[0].length);this.inLink=true;out+=this.outputLink(cap,{href:cap[2],title:cap[3]});this.inLink=false;continue}if((cap=this.rules.reflink.exec(src))||(cap=this.rules.nolink.exec(src))){src=src.substring(cap[0].length);link=(cap[2]||cap[1]).replace(/\s+/g," ");link=this.links[link.toLowerCase()];if(!link||!link.href){out+=cap[0].charAt(0);src=cap[0].substring(1)+src;continue}this.inLink=true;out+=this.outputLink(cap,link);this.inLink=false;continue}if(cap=this.rules.strong.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.strong(this.output(cap[2]||cap[1]));continue}if(cap=this.rules.em.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.em(this.output(cap[2]||cap[1]), cap.input);continue -}if(cap=this.rules.code.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.codespan(escape(cap[2],true));continue}if(cap=this.rules.br.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.br();continue}if(cap=this.rules.del.exec(src)){src=src.substring(cap[0].length);out+=this.renderer.del(this.output(cap[1]));continue}if(cap=this.rules.text.exec(src)){src=src.substring(cap[0].length);out+=escape(this.smartypants(cap[0]));continue}if(src){throw new Error("Infinite loop on byte: "+src.charCodeAt(0))}}return out};InlineLexer.prototype.outputLink=function(cap,link){var href=escape(link.href),title=link.title?escape(link.title):null;return cap[0].charAt(0)!=="!"?this.renderer.link(href,title,this.output(cap[1])):this.renderer.image(href,title,escape(cap[1]))};InlineLexer.prototype.smartypants=function(text){if(!this.options.smartypants){return text}return text.replace(/--/g,"\u2014").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1\u2018").replace(/'/g,"\u2019").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1\u201c").replace(/"/g,"\u201d").replace(/\.{3}/g,"\u2026")};InlineLexer.prototype.mangle=function(text){var out="",l=text.length,i=0,ch;for(;i0.5){ch="x"+ch.toString(16)}out+="&#"+ch+";"}return out};function Renderer(options){this.options=options||{}}Renderer.prototype.code=function(code,lang,escaped){if(this.options.highlight){var out=this.options.highlight(code,lang);if(out!=null&&out!==code){escaped=true;code=out}}if(!lang){return"
    "+(escaped?code:escape(code,true))+"\n
    "}return'
    '+(escaped?code:escape(code,true))+"\n
    \n"};Renderer.prototype.blockquote=function(quote){return"
    \n"+quote+"
    \n"};Renderer.prototype.html=function(html){return html};Renderer.prototype.heading=function(text,level,raw){return"'+text+"\n"};Renderer.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"};Renderer.prototype.list=function(body,ordered){var type=ordered?"ol":"ul";return"<"+type+">\n"+body+"\n"};Renderer.prototype.listitem=function(text){return"
  • "+text+"
  • \n"};Renderer.prototype.paragraph=function(text){return"

    "+text+"

    \n"};Renderer.prototype.table=function(header,body){return"\n"+"\n"+header+"\n"+"\n"+body+"\n"+"
    \n"};Renderer.prototype.tablerow=function(content){return"\n"+content+"\n"};Renderer.prototype.tablecell=function(content,flags){var type=flags.header?"th":"td";var tag=flags.align?"<"+type+' style="text-align:'+flags.align+'">':"<"+type+">";return tag+content+"\n"};Renderer.prototype.strong=function(text){return""+text+""};Renderer.prototype.em=function(text){return""+text+""};Renderer.prototype.codespan=function(text){return""+text+""};Renderer.prototype.br=function(){return this.options.xhtml?"
    ":"
    "};Renderer.prototype.del=function(text){return""+text+""};Renderer.prototype.link=function(href,title,text){if(this.options.sanitize){try{var prot=decodeURIComponent(unescape(href)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return""}if(prot.indexOf("javascript:")===0||prot.indexOf("vbscript:")===0){return""}}var out='
    ";return out};Renderer.prototype.image=function(href,title,text){var out=''+text+'":">";return out};function Parser(options){this.tokens=[];this.token=null;this.options=options||marked.defaults;this.options.renderer=this.options.renderer||new Renderer;this.renderer=this.options.renderer;this.renderer.options=this.options}Parser.parse=function(src,options,renderer){var parser=new Parser(options,renderer);return parser.parse(src)};Parser.prototype.parse=function(src){this.inline=new InlineLexer(src.links,this.options,this.renderer);this.tokens=src.reverse();var out="";while(this.next()){out+=this.tok()}return out};Parser.prototype.next=function(){return this.token=this.tokens.pop()};Parser.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0};Parser.prototype.parseText=function(){var body=this.token.text;while(this.peek().type==="text"){body+="\n"+this.next().text}return this.inline.output(body)};Parser.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,this.token.text);case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var header="",body="",i,row,cell,flags,j;cell="";for(i=0;i/g,">").replace(/"/g,""").replace(/'/g,"'")}function unescape(html){return html.replace(/&([#\w]+);/g,function(_,n){n=n.toLowerCase();if(n==="colon"){return":"}if(n.charAt(0)==="#"){return n.charAt(1)==="x"?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1))}return""})}function replace(regex,opt){regex=regex.source;opt=opt||"";return function self(name,val){if(!name){return new RegExp(regex,opt)}val=val.source||val;val=val.replace(/(^|[^\[])\^/g,"$1");regex=regex.replace(name,val);return self}}function noop(){}noop.exec=noop;function merge(obj){var i=1,target,key;for(;iAn error occured:

    "+escape(e.message+"",true)+"
    "}throw e}}marked.options=marked.setOptions=function(opt){merge(marked.defaults,opt);return marked};marked.defaults={gfm:true,tables:true,breaks:false,pedantic:false,sanitize:false,smartLists:false,silent:false,highlight:null,langPrefix:"lang-",smartypants:false,headerPrefix:"",renderer:new Renderer,xhtml:false};marked.Parser=Parser;marked.parser=Parser.parse;marked.Renderer=Renderer;marked.Lexer=Lexer;marked.lexer=Lexer.lex;marked.InlineLexer=InlineLexer;marked.inlineLexer=InlineLexer.output;marked.parse=marked;if(typeof module!=="undefined"&&typeof exports==="object"){module.exports=marked}else{if(typeof define==="function"&&define.amd){define(function(){return marked})}else{this.marked=marked}}}).call(function(){return this||(typeof window!=="undefined"?window:global)}()); +// 0.4.0 /^ *(#{1,6}) ——》/^ *(#{1,6}) 去掉了一个空格 TODO 行内公式带_ +/*if("string"!=typeof e)throw new Error("marked(): input parameter is of type "+Object.prototype.toString.call(e)+", string expected");*/ +// b(i[1].replace(/^ *| *\| *$/g,"")) --> i[1].replace(/^ *| *\| *$/g, "").split(/ *\| */) table没识别的问题 +// header.length===a.align.length --> header.length table没识别的问题 a.header.length -> a.cells[p].split('|').length - 2 +!function(e){"use strict";var t={newline:/^\n+/,code:/^( {4}[^\n]+\n*)+/,fences:d,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ *(#{1,6})*([^\n]+?) *(?:#+ *)?(?:\n+|$)/,nptable:d,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?\\?>\\n*|\\n*|\\n*|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$)|(?=\\h*\\n)[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,table:d,lheading:/^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading| {0,3}>|<\/?(?:tag)(?: +|\n|\/?>)|<(?:script|pre|style|!--))[^\n]+)*)/,text:/^[^\n]+/};function n(e){this.tokens=[],this.tokens.links={},this.options=e||m.defaults,this.rules=t.normal,this.options.pedantic?this.rules=t.pedantic:this.options.gfm&&(this.options.tables?this.rules=t.tables:this.rules=t.gfm)}t._label=/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,t._title=/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/,t.def=p(t.def).replace("label",t._label).replace("title",t._title).getRegex(),t.bullet=/(?:[*+-]|\d+\.)/,t.item=/^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/,t.item=p(t.item,"gm").replace(/bull/g,t.bullet).getRegex(),t.list=p(t.list).replace(/bull/g,t.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+t.def.source+")").getRegex(),t._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",t._comment=//,t.html=p(t.html,"i").replace("comment",t._comment).replace("tag",t._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),t.paragraph=p(t.paragraph).replace("hr",t.hr).replace("heading",t.heading).replace("lheading",t.lheading).replace("tag",t._tag).getRegex(),t.blockquote=p(t.blockquote).replace("paragraph",t.paragraph).getRegex(),t.normal=f({},t),t.gfm=f({},t.normal,{fences:/^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\n? *\1 *(?:\n+|$)/,paragraph:/^/,heading:/^ *(#{1,6})+([^\n]+?) *#* *(?:\n+|$)/}),t.gfm.paragraph=p(t.paragraph).replace("(?!","(?!"+t.gfm.fences.source.replace("\\1","\\2")+"|"+t.list.source.replace("\\1","\\3")+"|").getRegex(),t.tables=f({},t.gfm,{nptable:/^ *([^|\n ].*\|.*)\n *([-:]+ *\|[-| :]*)(?:\n((?:.*[^>\n ].*(?:\n|$))*)\n*|$)/,table:/^ *\|(.+)\n *\|?( *[-:]+[-| :]*)(?:\n((?: *[^>\n ].*(?:\n|$))*)\n*|$)/}),t.pedantic=f({},t.normal,{html:p("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",t._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/}),n.rules=t,n.lex=function(e,t){return new n(t).lex(e)},n.prototype.lex=function(e){return e=e.replace(/\r\n|\r/g,"\n").replace(/\t/g," ").replace(/\u00a0/g," ").replace(/\u2424/g,"\n"),this.token(e,!0)},n.prototype.token=function(e,n){var r,s,i,l,o,a,h,p,u,c,g,d,f;for(e=e.replace(/^ +$/gm,"");e;)if((i=this.rules.newline.exec(e))&&(e=e.substring(i[0].length),i[0].length>1&&this.tokens.push({type:"space"})),i=this.rules.code.exec(e))e=e.substring(i[0].length),i=i[0].replace(/^ {4}/gm,""),this.tokens.push({type:"code",text:this.options.pedantic?i:i.replace(/\n+$/,"")});else if(i=this.rules.fences.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"code",lang:i[2],text:i[3]||""});else if(i=this.rules.heading.exec(e))e=e.substring(i[0].length),this.tokens.push({type:"heading",depth:i[1].length,text:i[2]});else if(n&&(i=this.rules.nptable.exec(e))&&(a={type:"table",header:i[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3]?i[3].replace(/\n$/,"").split("\n"):[]}).header.length){for(e=e.substring(i[0].length),p=0;p ?/gm,""),this.token(i,n),this.tokens.push({type:"blockquote_end"});else if(i=this.rules.list.exec(e)){for(e=e.substring(i[0].length),g=(l=i[2]).length>1,this.tokens.push({type:"list_start",ordered:g,start:g?+l:""}),r=!1,c=(i=i[0].match(this.rules.item)).length,p=0;p1&&o.length>1||(e=i.slice(p+1).join("\n")+e,p=c-1)),s=r||/\n\n(?!\s*$)/.test(a),p!==c-1&&(r="\n"===a.charAt(a.length-1),s||(s=r)),f=void 0,(d=/^\[[ xX]\] /.test(a))&&(f=" "!==a[1],a=a.replace(/^\[[ xX]\] +/,"")),this.tokens.push({type:s?"loose_item_start":"list_item_start",task:d,checked:f}),this.token(a,!1),this.tokens.push({type:"list_item_end"});this.tokens.push({type:"list_end"})}else if(i=this.rules.html.exec(e))e=e.substring(i[0].length),this.tokens.push({type:this.options.sanitize?"paragraph":"html",pre:!this.options.sanitizer&&("pre"===i[1]||"script"===i[1]||"style"===i[1]),text:i[0]});else if(n&&(i=this.rules.def.exec(e)))e=e.substring(i[0].length),i[3]&&(i[3]=i[3].substring(1,i[3].length-1)),u=i[1].toLowerCase().replace(/\s+/g," "),this.tokens.links[u]||(this.tokens.links[u]={href:i[2],title:i[3]});else if(n&&(i=this.rules.table.exec(e))&&(a={type:"table",header:i[1].replace(/^ *| *\| *$/g, "").split(/ *\| */),align:i[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:i[3]?i[3].replace(/(?: *\| *)?\n$/,"").split("\n"):[]}).header.length){for(e=e.substring(i[0].length),p=0;p?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:d,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(href(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,strong:/^__([^\s][\s\S]*?[^\s])__(?!_)|^\*\*([^\s][\s\S]*?[^\s])\*\*(?!\*)|^__([^\s])__(?!_)|^\*\*([^\s])\*\*(?!\*)/,em:/^_([^\s][\s\S]*?[^\s_])_(?!_)|^_([^\s_][\s\S]*?[^\s])_(?!_)|^\*([^\s][\s\S]*?[^\s*])\*(?!\*)|^\*([^\s*][\s\S]*?[^\s])\*(?!\*)|^_([^\s_])_(?!_)|^\*([^\s*])\*(?!\*)/,code:/^(`+)\s*([\s\S]*?[^`]?)\s*\1(?!`)/,br:/^ {2,}\n(?!\s*$)/,del:d,text:/^[\s\S]+?(?=[\\/g,">").replace(/"/g,""").replace(/'/g,"'")}function h(e){return e.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi,function(e,t){return"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""})}function p(e,t){return e=e.source||e,t=t||"",{replace:function(t,n){return n=(n=n.source||n).replace(/(^|[^\[])\^/g,"$1"),e=e.replace(t,n),this},getRegex:function(){return new RegExp(e,t)}}}function u(e,t){return c[" "+e]||(/^[^:]+:\/*[^/]*$/.test(e)?c[" "+e]=e+"/":c[" "+e]=e.replace(/[^/]*$/,"")),e=c[" "+e],"//"===t.slice(0,2)?e.replace(/:[\s\S]*/,":")+t:"/"===t.charAt(0)?e.replace(/(:\/*[^/]*)[\s\S]*/,"$1")+t:e+t}r._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,r._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,r._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,r.autolink=p(r.autolink).replace("scheme",r._scheme).replace("email",r._email).getRegex(),r._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,r.tag=p(r.tag).replace("comment",t._comment).replace("attribute",r._attribute).getRegex(),r._label=/(?:\[[^\[\]]*\]|\\[\[\]]?|`[^`]*`|[^\[\]\\])*?/,r._href=/\s*(<(?:\\[<>]?|[^\s<>\\])*>|(?:\\[()]?|\([^\s\x00-\x1f()\\]*\)|[^\s\x00-\x1f()\\])*?)/,r._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,r.link=p(r.link).replace("label",r._label).replace("href",r._href).replace("title",r._title).getRegex(),r.reflink=p(r.reflink).replace("label",r._label).getRegex(),r.normal=f({},r),r.pedantic=f({},r.normal,{strong:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,em:/^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/,link:p(/^!?\[(label)\]\((.*?)\)/).replace("label",r._label).getRegex(),reflink:p(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",r._label).getRegex()}),r.gfm=f({},r.normal,{escape:p(r.escape).replace("])","~|])").getRegex(),url:p(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/).replace("email",r._email).getRegex(),_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^~~(?=\S)([\s\S]*?\S)~~/,text:p(r.text).replace("]|","~]|").replace("|","|https?://|ftp://|www\\.|[a-zA-Z0-9.!#$%&'*+/=?^_`{\\|}~-]+@|").getRegex()}),r.breaks=f({},r.gfm,{br:p(r.br).replace("{2,}","*").getRegex(),text:p(r.gfm.text).replace("{2,}","*").getRegex()}),s.rules=r,s.output=function(e,t,n){return new s(t,n).output(e)},s.prototype.output=function(e){for(var t,n,r,i,l,o="";e;)if(l=this.rules.escape.exec(e))e=e.substring(l[0].length),o+=l[1];else if(l=this.rules.autolink.exec(e))e=e.substring(l[0].length),r="@"===l[2]?"mailto:"+(n=a(this.mangle(l[1]))):n=a(l[1]),o+=this.renderer.link(r,null,n);else if(this.inLink||!(l=this.rules.url.exec(e))){if(l=this.rules.tag.exec(e))!this.inLink&&/^
    /i.test(l[0])&&(this.inLink=!1),e=e.substring(l[0].length),o+=this.options.sanitize?this.options.sanitizer?this.options.sanitizer(l[0]):a(l[0]):l[0];else if(l=this.rules.link.exec(e))e=e.substring(l[0].length),this.inLink=!0,r=l[2],this.options.pedantic?(t=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(r))?(r=t[1],i=t[3]):i="":i=l[3]?l[3].slice(1,-1):"",r=r.trim().replace(/^<([\s\S]*)>$/,"$1"),o+=this.outputLink(l,{href:s.escapes(r),title:s.escapes(i)}),this.inLink=!1;else if((l=this.rules.reflink.exec(e))||(l=this.rules.nolink.exec(e))){if(e=e.substring(l[0].length),t=(l[2]||l[1]).replace(/\s+/g," "),!(t=this.links[t.toLowerCase()])||!t.href){o+=l[0].charAt(0),e=l[0].substring(1)+e;continue}this.inLink=!0,o+=this.outputLink(l,t),this.inLink=!1}else if(l=this.rules.strong.exec(e))e=e.substring(l[0].length),o+=this.renderer.strong(this.output(l[4]||l[3]||l[2]||l[1]));else if(l=this.rules.em.exec(e))e=e.substring(l[0].length),o+=this.renderer.em(this.output(l[6]||l[5]||l[4]||l[3]||l[2]||l[1]));else if(l=this.rules.code.exec(e))e=e.substring(l[0].length),o+=this.renderer.codespan(a(l[2].trim(),!0));else if(l=this.rules.br.exec(e))e=e.substring(l[0].length),o+=this.renderer.br();else if(l=this.rules.del.exec(e))e=e.substring(l[0].length),o+=this.renderer.del(this.output(l[1]));else if(l=this.rules.text.exec(e))e=e.substring(l[0].length),o+=this.renderer.text(a(this.smartypants(l[0])));else if(e)throw new Error("Infinite loop on byte: "+e.charCodeAt(0))}else l[0]=this.rules._backpedal.exec(l[0])[0],e=e.substring(l[0].length),"@"===l[2]?r="mailto:"+(n=a(l[0])):(n=a(l[0]),r="www."===l[1]?"http://"+n:n),o+=this.renderer.link(r,null,n);return o},s.escapes=function(e){return e?e.replace(s.rules._escapes,"$1"):e},s.prototype.outputLink=function(e,t){var n=t.href,r=t.title?a(t.title):null;return"!"!==e[0].charAt(0)?this.renderer.link(n,r,this.output(e[1])):this.renderer.image(n,r,a(e[1]))},s.prototype.smartypants=function(e){return this.options.smartypants?e.replace(/---/g,"—").replace(/--/g,"–").replace(/(^|[-\u2014/(\[{"\s])'/g,"$1‘").replace(/'/g,"’").replace(/(^|[-\u2014/(\[{\u2018\s])"/g,"$1“").replace(/"/g,"”").replace(/\.{3}/g,"…"):e},s.prototype.mangle=function(e){if(!this.options.mangle)return e;for(var t,n="",r=e.length,s=0;s.5&&(t="x"+t.toString(16)),n+="&#"+t+";";return n},i.prototype.code=function(e,t,n){if(this.options.highlight){var r=this.options.highlight(e,t);null!=r&&r!==e&&(n=!0,e=r)}return t?'
    '+(n?e:a(e,!0))+"
    \n":"
    "+(n?e:a(e,!0))+"
    "},i.prototype.blockquote=function(e){return"
    \n"+e+"
    \n"},i.prototype.html=function(e){return e},i.prototype.heading=function(e,t,n){return this.options.headerIds?"'+e+"\n":""+e+"\n"},i.prototype.hr=function(){return this.options.xhtml?"
    \n":"
    \n"},i.prototype.list=function(e,t,n){var r=t?"ol":"ul";return"<"+r+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"\n"},i.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},i.prototype.checkbox=function(e){return" "},i.prototype.paragraph=function(e){return"

    "+e+"

    \n"},i.prototype.table=function(e,t){return t&&(t=""+t+""),"\n\n"+e+"\n"+t+"
    \n"},i.prototype.tablerow=function(e){return"\n"+e+"\n"},i.prototype.tablecell=function(e,t){var n=t.header?"th":"td";return(t.align?"<"+n+' align="'+t.align+'">':"<"+n+">")+e+"\n"},i.prototype.strong=function(e){return""+e+""},i.prototype.em=function(e){return""+e+""},i.prototype.codespan=function(e){return""+e+""},i.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},i.prototype.del=function(e){return""+e+""},i.prototype.link=function(e,t,n){if(this.options.sanitize){try{var r=decodeURIComponent(h(e)).replace(/[^\w:]/g,"").toLowerCase()}catch(e){return n}if(0===r.indexOf("javascript:")||0===r.indexOf("vbscript:")||0===r.indexOf("data:"))return n}this.options.baseUrl&&!g.test(e)&&(e=u(this.options.baseUrl,e));try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return n}var s='
    "},i.prototype.image=function(e,t,n){this.options.baseUrl&&!g.test(e)&&(e=u(this.options.baseUrl,e));var r=''+n+'":">"},i.prototype.text=function(e){return e},l.prototype.strong=l.prototype.em=l.prototype.codespan=l.prototype.del=l.prototype.text=function(e){return e},l.prototype.link=l.prototype.image=function(e,t,n){return""+n},l.prototype.br=function(){return""},o.parse=function(e,t){return new o(t).parse(e)},o.prototype.parse=function(e){this.inline=new s(e.links,this.options),this.inlineText=new s(e.links,f({},this.options,{renderer:new l})),this.tokens=e.reverse();for(var t="";this.next();)t+=this.tok();return t},o.prototype.next=function(){return this.token=this.tokens.pop()},o.prototype.peek=function(){return this.tokens[this.tokens.length-1]||0},o.prototype.parseText=function(){for(var e=this.token.text;"text"===this.peek().type;)e+="\n"+this.next().text;return this.inline.output(e)},o.prototype.tok=function(){switch(this.token.type){case"space":return"";case"hr":return this.renderer.hr();case"heading":return this.renderer.heading(this.inline.output(this.token.text),this.token.depth,h(this.inlineText.output(this.token.text)));case"code":return this.renderer.code(this.token.text,this.token.lang,this.token.escaped);case"table":var e,t,n,r,s="",i="";for(n="",e=0;et)n.splice(t);else for(;n.lengthAn error occurred:

    "+a(e.message+"",!0)+"
    ";throw e}}d.exec=d,m.options=m.setOptions=function(e){return f(m.defaults,e),m},m.getDefaults=function(){return{baseUrl:null,breaks:!1,gfm:!0,headerIds:!0,headerPrefix:"",highlight:null,langPrefix:"language-",mangle:!0,pedantic:!1,renderer:new i,sanitize:!1,sanitizer:null,silent:!1,smartLists:!1,smartypants:!1,tables:!0,xhtml:!1}},m.defaults=m.getDefaults(),m.Parser=o,m.parser=o.parse,m.Renderer=i,m.TextRenderer=l,m.Lexer=n,m.lexer=n.lex,m.InlineLexer=s,m.inlineLexer=s.output,m.parse=m,"undefined"!=typeof module&&"object"==typeof exports?module.exports=m:"function"==typeof define&&define.amd?define(function(){return m}):e.marked=m}(this||("undefined"!=typeof window?window:global)); + diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js index 8045580e9..a04ec614c 100644 --- a/public/react/config/webpack.config.dev.js +++ b/public/react/config/webpack.config.dev.js @@ -32,7 +32,7 @@ module.exports = { // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s // devtool: "cheap-module-eval-source-map", // 开启调试 - devtool: "eval", // 开启调试 + // devtool: "eval", // 开启调试 // These are the "entry points" to our application. // This means they will be the "root" imports that are included in JS bundle. // The first two entry points enable "hot" CSS and auto-refreshes for JS. @@ -197,6 +197,21 @@ module.exports = { }, ], }, + { + test: /\.scss$/, + use: [ + require.resolve("style-loader"), + { + loader: require.resolve("css-loader"), + options: { + importLoaders: 1, + }, + }, + { + loader: require.resolve("sass-loader") + } + ], + }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js index ddc111b9c..84dbffd3b 100644 --- a/public/react/config/webpack.config.prod.js +++ b/public/react/config/webpack.config.prod.js @@ -1,5 +1,5 @@ 'use strict'; - +// extract-css-assets-webpack-plugin const autoprefixer = require('autoprefixer'); const path = require('path'); const webpack = require('webpack'); @@ -224,6 +224,23 @@ module.exports = { ), // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, + { + test: /\.scss$/, + use: [ + require.resolve("style-loader"), + { + loader: require.resolve("css-loader"), + options: { + importLoaders: 1, + minimize: true, + sourceMap: shouldUseSourceMap, + }, + }, + { + loader: require.resolve("sass-loader") + } + ], + }, // "file" loader makes sure assets end up in the `build` folder. // When you `import` an asset, you get its filename. // This loader doesn't use a "test" so it will catch all modules diff --git a/public/react/package-lock.json b/public/react/package-lock.json index 8f387e045..631da270e 100644 --- a/public/react/package-lock.json +++ b/public/react/package-lock.json @@ -4,20 +4,6 @@ "lockfileVersion": 1, "requires": true, "dependencies": { - "@ant-design/icons": { - "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/@ant-design/icons/download/@ant-design/icons-1.2.1.tgz", - "integrity": "sha1-jhkwGxQz7GfWu9DoknguKt5WH/k=" - }, - "@ant-design/icons-react": { - "version": "1.1.5", - "resolved": "http://registry.npm.taobao.org/@ant-design/icons-react/download/@ant-design/icons-react-1.1.5.tgz", - "integrity": "sha1-GwPajcztKku5gu97JcHSQBTDWmg=", - "requires": { - "ant-design-palettes": "^1.1.3", - "babel-runtime": "^6.26.0" - } - }, "@babel/helper-annotate-as-pure": { "version": "7.0.0", "resolved": "http://registry.npm.taobao.org/@babel/helper-annotate-as-pure/download/@babel/helper-annotate-as-pure-7.0.0.tgz", @@ -95,15 +81,10 @@ "resolved": "http://registry.npm.taobao.org/@emotion/unitless/download/@emotion/unitless-0.7.3.tgz", "integrity": "sha1-YxCgR/EtIaEDb7AxMXIZiSRAQW8=" }, - "@flatten/array": { - "version": "1.1.7", - "resolved": "https://registry.npm.taobao.org/@flatten/array/download/@flatten/array-1.1.7.tgz", - "integrity": "sha1-+UZZu/MtVY9pKmI0MEokcxKm+jg=" - }, "@icedesign/base": { - "version": "0.2.7", - "resolved": "http://registry.npm.taobao.org/@icedesign/base/download/@icedesign/base-0.2.7.tgz", - "integrity": "sha1-cFvLHH1UQVQKYuvsJRsGh56oN+U=", + "version": "0.2.8", + "resolved": "https://registry.npm.taobao.org/@icedesign/base/download/@icedesign/base-0.2.8.tgz", + "integrity": "sha1-hmlSY+17gnKJB3sbgoy446sqzAk=", "requires": { "async-validator": "^1.6.7", "classnames": "^2.2.3", @@ -147,14 +128,6 @@ "csstype": "^2.2.0" } }, - "@types/react-slick": { - "version": "0.23.3", - "resolved": "http://registry.npm.taobao.org/@types/react-slick/download/@types/react-slick-0.23.3.tgz", - "integrity": "sha1-ydFDI6dfVPRqZS+3Rf5VOq0JHOA=", - "requires": { - "@types/react": "*" - } - }, "@types/react-transition-group": { "version": "2.9.0", "resolved": "http://registry.npm.taobao.org/@types/react-transition-group/download/@types/react-transition-group-2.9.0.tgz?cache=0&other_urls=http%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Freact-transition-group%2Fdownload%2F%40types%2Freact-transition-group-2.9.0.tgz", @@ -333,102 +306,6 @@ "color-convert": "^1.9.0" } }, - "ant-design-palettes": { - "version": "1.1.3", - "resolved": "http://registry.npm.taobao.org/ant-design-palettes/download/ant-design-palettes-1.1.3.tgz", - "integrity": "sha1-hBGbGk2GNjrcUqONWH5lM2oKJ90=", - "requires": { - "tinycolor2": "^1.4.1" - } - }, - "antd": { - "version": "3.16.2", - "resolved": "http://registry.npm.taobao.org/antd/download/antd-3.16.2.tgz", - "integrity": "sha1-o7SoRKbegubIfJb4jdojF/TYkHU=", - "requires": { - "@ant-design/icons": "~1.2.0", - "@ant-design/icons-react": "~1.1.2", - "@types/react-slick": "^0.23.3", - "array-tree-filter": "^2.1.0", - "babel-runtime": "6.x", - "classnames": "~2.2.6", - "copy-to-clipboard": "^3.0.8", - "create-react-class": "^15.6.3", - "create-react-context": "0.2.2", - "css-animation": "^1.5.0", - "dom-closest": "^0.2.0", - "enquire.js": "^2.1.6", - "lodash": "^4.17.11", - "moment": "^2.24.0", - "omit.js": "^1.0.0", - "prop-types": "^15.6.2", - "raf": "^3.4.0", - "rc-animate": "^2.5.4", - "rc-calendar": "~9.12.1", - "rc-cascader": "~0.17.0", - "rc-checkbox": "~2.1.5", - "rc-collapse": "~1.11.1", - "rc-dialog": "~7.3.0", - "rc-drawer": "~1.7.6", - "rc-dropdown": "~2.4.1", - "rc-editor-mention": "^1.1.7", - "rc-form": "^2.4.0", - "rc-input-number": "~4.4.0", - "rc-menu": "~7.4.12", - "rc-notification": "~3.3.0", - "rc-pagination": "~1.17.7", - "rc-progress": "~2.3.0", - "rc-rate": "~2.5.0", - "rc-select": "~9.0.0", - "rc-slider": "~8.6.5", - "rc-steps": "~3.3.0", - "rc-switch": "~1.9.0", - "rc-table": "~6.4.0", - "rc-tabs": "~9.6.0", - "rc-time-picker": "~3.6.1", - "rc-tooltip": "~3.7.3", - "rc-tree": "~1.15.2", - "rc-tree-select": "~2.6.0", - "rc-trigger": "^2.6.2", - "rc-upload": "~2.6.0", - "rc-util": "^4.5.1", - "react-lazy-load": "^3.0.13", - "react-lifecycles-compat": "^3.0.4", - "react-slick": "~0.23.2", - "resize-observer-polyfill": "^1.5.0", - "shallowequal": "^1.1.0", - "warning": "~4.0.2" - }, - "dependencies": { - "rc-select": { - "version": "9.0.2", - "resolved": "http://registry.npm.taobao.org/rc-select/download/rc-select-9.0.2.tgz", - "integrity": "sha1-zg0pfbX4pcfou8P8JNntW6ZIASw=", - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "2.x", - "component-classes": "1.x", - "dom-scroll-into-view": "1.x", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "2.x", - "rc-menu": "^7.3.0", - "rc-trigger": "^2.5.4", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.2", - "warning": "^4.0.2" - } - }, - "warning": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, "anymatch": { "version": "1.3.2", "resolved": "http://registry.npm.taobao.org/anymatch/download/anymatch-1.3.2.tgz", @@ -520,11 +397,6 @@ "resolved": "http://registry.npm.taobao.org/array-reduce/download/array-reduce-0.0.0.tgz", "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=" }, - "array-tree-filter": { - "version": "2.1.0", - "resolved": "http://registry.npm.taobao.org/array-tree-filter/download/array-tree-filter-2.1.0.tgz", - "integrity": "sha1-hzrAD+yDdJ8lWsjdCDgUtPYykZA=" - }, "array-union": { "version": "1.0.2", "resolved": "http://registry.npm.taobao.org/array-union/download/array-union-1.0.2.tgz", @@ -629,12 +501,9 @@ "dev": true }, "async-validator": { - "version": "1.11.0", - "resolved": "http://registry.npm.taobao.org/async-validator/download/async-validator-1.11.0.tgz", - "integrity": "sha1-9i/RS8yjNvzalubdU9vR3dP8MZg=", - "requires": { - "babel-runtime": "6.x" - } + "version": "1.12.2", + "resolved": "https://registry.npm.taobao.org/async-validator/download/async-validator-1.12.2.tgz", + "integrity": "sha1-vq5nHnF00pOLe0tp0vt+cit/1yw=" }, "asynckit": { "version": "0.4.0", @@ -2825,14 +2694,6 @@ "resolved": "http://registry.npm.taobao.org/copy-descriptor/download/copy-descriptor-0.1.1.tgz", "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, - "copy-to-clipboard": { - "version": "3.1.0", - "resolved": "http://registry.npm.taobao.org/copy-to-clipboard/download/copy-to-clipboard-3.1.0.tgz", - "integrity": "sha1-CigUGJnmvSF7ncE/0WibOziCC0Q=", - "requires": { - "toggle-selection": "^1.0.6" - } - }, "core-js": { "version": "2.6.5", "resolved": "http://registry.npm.taobao.org/core-js/download/core-js-2.6.5.tgz", @@ -2916,18 +2777,9 @@ "object-assign": "^4.1.1" } }, - "create-react-context": { - "version": "0.2.2", - "resolved": "http://registry.npm.taobao.org/create-react-context/download/create-react-context-0.2.2.tgz", - "integrity": "sha1-mDZUL5qqIoaM19Sm+CZn3zgBnco=", - "requires": { - "fbjs": "^0.8.0", - "gud": "^1.0.0" - } - }, "cropperjs": { "version": "0.7.2", - "resolved": "http://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz", + "resolved": "https://registry.npm.taobao.org/cropperjs/download/cropperjs-0.7.2.tgz", "integrity": "sha1-atinHbAGKbqULZzt5lKyeXXp50o=" }, "cross-spawn": { @@ -3494,14 +3346,6 @@ "resolved": "http://registry.npm.taobao.org/dom-align/download/dom-align-1.8.2.tgz", "integrity": "sha1-/c02vOJbqNNP41gu/Vesdn30kL0=" }, - "dom-closest": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz", - "integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=", - "requires": { - "dom-matches": ">=1.0.1" - } - }, "dom-converter": { "version": "0.2.0", "resolved": "http://registry.npm.taobao.org/dom-converter/download/dom-converter-0.2.0.tgz", @@ -3533,11 +3377,6 @@ } } }, - "dom-matches": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz", - "integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw=" - }, "dom-scroll-into-view": { "version": "1.2.1", "resolved": "http://registry.npm.taobao.org/dom-scroll-into-view/download/dom-scroll-into-view-1.2.1.tgz", @@ -3610,23 +3449,6 @@ "resolved": "http://registry.npm.taobao.org/dotenv-expand/download/dotenv-expand-4.2.0.tgz", "integrity": "sha1-3vHxyl1gWdJKdm5YeULCEQbOEnU=" }, - "draft-js": { - "version": "0.10.5", - "resolved": "http://registry.npm.taobao.org/draft-js/download/draft-js-0.10.5.tgz", - "integrity": "sha1-v6m+sBj+BTPbsI1mdcNxprCPp0I=", - "requires": { - "fbjs": "^0.8.15", - "immutable": "~3.7.4", - "object-assign": "^4.1.0" - }, - "dependencies": { - "immutable": { - "version": "3.7.6", - "resolved": "http://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz", - "integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks=" - } - } - }, "duplexer": { "version": "0.1.1", "resolved": "http://registry.npm.taobao.org/duplexer/download/duplexer-0.1.1.tgz", @@ -4220,11 +4042,6 @@ "resolved": "http://registry.npm.taobao.org/eventemitter3/download/eventemitter3-3.1.0.tgz", "integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=" }, - "eventlistener": { - "version": "0.0.1", - "resolved": "http://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz", - "integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg=" - }, "events": { "version": "3.0.0", "resolved": "http://registry.npm.taobao.org/events/download/events-3.0.0.tgz", @@ -5306,11 +5123,6 @@ "resolved": "http://registry.npm.taobao.org/growly/download/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=" }, - "gud": { - "version": "1.0.0", - "resolved": "http://registry.npm.taobao.org/gud/download/gud-1.0.0.tgz", - "integrity": "sha1-pIlYGxfmpwvsqavjrlfeekmYUsA=" - }, "gzip-size": { "version": "3.0.0", "resolved": "http://registry.npm.taobao.org/gzip-size/download/gzip-size-3.0.0.tgz", @@ -5319,11 +5131,6 @@ "duplexer": "^0.1.1" } }, - "hammerjs": { - "version": "2.0.8", - "resolved": "http://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz", - "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" - }, "handle-thing": { "version": "1.2.5", "resolved": "http://registry.npm.taobao.org/handle-thing/download/handle-thing-1.2.5.tgz", @@ -6713,14 +6520,6 @@ "resolved": "http://registry.npm.taobao.org/json-stringify-safe/download/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "json2mq": { - "version": "0.2.0", - "resolved": "http://registry.npm.taobao.org/json2mq/download/json2mq-0.2.0.tgz", - "integrity": "sha1-tje9O6nqvhIsg+lyBIOusQ0skEo=", - "requires": { - "string-convert": "^0.2.0" - } - }, "json3": { "version": "3.3.2", "resolved": "http://registry.npm.taobao.org/json3/download/json3-3.3.2.tgz", @@ -7100,11 +6899,6 @@ "lodash._reinterpolate": "~3.0.0" } }, - "lodash.throttle": { - "version": "4.1.1", - "resolved": "http://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz", - "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" - }, "lodash.uniq": { "version": "4.5.0", "resolved": "http://registry.npm.taobao.org/lodash.uniq/download/lodash.uniq-4.5.0.tgz", @@ -7808,14 +7602,6 @@ "resolved": "http://registry.npm.taobao.org/obuf/download/obuf-1.1.2.tgz", "integrity": "sha1-Cb6jND1BhZ69RGKS0RydTbYZCE4=" }, - "omit.js": { - "version": "1.0.2", - "resolved": "http://registry.npm.taobao.org/omit.js/download/omit.js-1.0.2.tgz", - "integrity": "sha1-kaFPDrqEBm36AVvzDkdMR/MLyFg=", - "requires": { - "babel-runtime": "^6.23.0" - } - }, "on-finished": { "version": "2.3.0", "resolved": "http://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", @@ -9333,11 +9119,6 @@ "resolved": "http://registry.npm.taobao.org/preserve/download/preserve-0.2.0.tgz", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" }, - "prettier": { - "version": "1.17.0", - "resolved": "http://registry.npm.taobao.org/prettier/download/prettier-1.17.0.tgz", - "integrity": "sha1-U7MDZ27tIswUqfDOwJtHezAmwAg=" - }, "pretty-bytes": { "version": "4.0.2", "resolved": "http://registry.npm.taobao.org/pretty-bytes/download/pretty-bytes-4.0.2.tgz", @@ -9603,130 +9384,6 @@ "react-lifecycles-compat": "^3.0.4" } }, - "rc-calendar": { - "version": "9.12.4", - "resolved": "http://registry.npm.taobao.org/rc-calendar/download/rc-calendar-9.12.4.tgz", - "integrity": "sha1-aO46hXtTQdeA2Uc1QZJs/gtEkVQ=", - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", - "rc-util": "^4.1.1", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-cascader": { - "version": "0.17.1", - "resolved": "http://registry.npm.taobao.org/rc-cascader/download/rc-cascader-0.17.1.tgz", - "integrity": "sha1-kUSBwzcLX9j4Lk+d+bZZbf7aFNU=", - "requires": { - "array-tree-filter": "^2.1.0", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.4", - "shallow-equal": "^1.0.0", - "warning": "^4.0.1" - }, - "dependencies": { - "warning": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "rc-checkbox": { - "version": "2.1.6", - "resolved": "http://registry.npm.taobao.org/rc-checkbox/download/rc-checkbox-2.1.6.tgz", - "integrity": "sha1-XcAGU+UncBjEMf7FXji5HB+XbpA=", - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "2.x", - "prop-types": "15.x", - "rc-util": "^4.0.4" - } - }, - "rc-collapse": { - "version": "1.11.1", - "resolved": "http://registry.npm.taobao.org/rc-collapse/download/rc-collapse-1.11.1.tgz", - "integrity": "sha1-SqCXetv1Ip19tYIFZGsTkFrdcq0=", - "requires": { - "classnames": "2.x", - "css-animation": "1.x", - "prop-types": "^15.5.6", - "rc-animate": "2.x", - "react-is": "^16.7.0", - "shallowequal": "^1.1.0" - } - }, - "rc-dialog": { - "version": "7.3.1", - "resolved": "http://registry.npm.taobao.org/rc-dialog/download/rc-dialog-7.3.1.tgz", - "integrity": "sha1-RQQew1v8jjN8kbZLUs6+9upc1KI=", - "requires": { - "babel-runtime": "6.x", - "rc-animate": "2.x", - "rc-util": "^4.4.0" - } - }, - "rc-drawer": { - "version": "1.7.7", - "resolved": "http://registry.npm.taobao.org/rc-drawer/download/rc-drawer-1.7.7.tgz", - "integrity": "sha1-sBTR3lJFfIXE8+Hw1kelQDHdJgw=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.0", - "rc-util": "^4.5.1" - } - }, - "rc-dropdown": { - "version": "2.4.1", - "resolved": "http://registry.npm.taobao.org/rc-dropdown/download/rc-dropdown-2.4.1.tgz", - "integrity": "sha1-qu9us6UVLN2ZgolcKnjZtfBGzew=", - "requires": { - "babel-runtime": "^6.26.0", - "classnames": "^2.2.6", - "prop-types": "^15.5.8", - "rc-trigger": "^2.5.1", - "react-lifecycles-compat": "^3.0.2" - } - }, - "rc-editor-core": { - "version": "0.8.9", - "resolved": "http://registry.npm.taobao.org/rc-editor-core/download/rc-editor-core-0.8.9.tgz", - "integrity": "sha1-9hGVLI7tll4+NI2ErnvohdrrIhw=", - "requires": { - "babel-runtime": "^6.26.0", - "classnames": "^2.2.5", - "draft-js": "^0.10.0", - "immutable": "^3.7.4", - "lodash": "^4.16.5", - "prop-types": "^15.5.8", - "setimmediate": "^1.0.5" - } - }, - "rc-editor-mention": { - "version": "1.1.12", - "resolved": "http://registry.npm.taobao.org/rc-editor-mention/download/rc-editor-mention-1.1.12.tgz", - "integrity": "sha1-iWvLFyES8YgS6W/dM7pgPA/HMGo=", - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "^2.2.5", - "dom-scroll-into-view": "^1.2.0", - "draft-js": "~0.10.0", - "immutable": "^3.7.4", - "prop-types": "^15.5.8", - "rc-animate": "^2.3.0", - "rc-editor-core": "~0.8.3" - } - }, "rc-form": { "version": "2.4.4", "resolved": "http://registry.npm.taobao.org/rc-form/download/rc-form-2.4.4.tgz", @@ -9759,28 +9416,6 @@ } } }, - "rc-hammerjs": { - "version": "0.6.9", - "resolved": "http://registry.npm.taobao.org/rc-hammerjs/download/rc-hammerjs-0.6.9.tgz", - "integrity": "sha1-mk3b2hsuyPm5WWCRpqmJhCokOQc=", - "requires": { - "babel-runtime": "6.x", - "hammerjs": "^2.0.8", - "prop-types": "^15.5.9" - } - }, - "rc-input-number": { - "version": "4.4.1", - "resolved": "http://registry.npm.taobao.org/rc-input-number/download/rc-input-number-4.4.1.tgz", - "integrity": "sha1-FjbPKBzejXjqTIuf/P/Xe4A1BnU=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.0", - "prop-types": "^15.5.7", - "rc-util": "^4.5.1", - "rmc-feedback": "^2.0.0" - } - }, "rc-menu": { "version": "7.4.22", "resolved": "http://registry.npm.taobao.org/rc-menu/download/rc-menu-7.4.22.tgz", @@ -9799,18 +9434,6 @@ "resize-observer-polyfill": "^1.5.0" } }, - "rc-notification": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/rc-notification/download/rc-notification-3.3.1.tgz", - "integrity": "sha1-C6o+cPjUCrAVzo+njCYMSQ/HvrQ=", - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "prop-types": "^15.5.8", - "rc-animate": "2.x", - "rc-util": "^4.0.4" - } - }, "rc-pagination": { "version": "1.17.14", "resolved": "http://registry.npm.taobao.org/rc-pagination/download/rc-pagination-1.17.14.tgz", @@ -9821,15 +9444,6 @@ "react-lifecycles-compat": "^3.0.4" } }, - "rc-progress": { - "version": "2.3.0", - "resolved": "http://registry.npm.taobao.org/rc-progress/download/rc-progress-2.3.0.tgz", - "integrity": "sha1-z70H/5AmxFAQCYDeIJqSZQ4k8xM=", - "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8" - } - }, "rc-rate": { "version": "2.5.0", "resolved": "http://registry.npm.taobao.org/rc-rate/download/rc-rate-2.5.0.tgz", @@ -9870,116 +9484,6 @@ } } }, - "rc-slider": { - "version": "8.6.9", - "resolved": "http://registry.npm.taobao.org/rc-slider/download/rc-slider-8.6.9.tgz", - "integrity": "sha1-syFIpJjJJ8k/INwflehoLEkkv44=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "prop-types": "^15.5.4", - "rc-tooltip": "^3.7.0", - "rc-util": "^4.0.4", - "shallowequal": "^1.0.1", - "warning": "^4.0.3" - }, - "dependencies": { - "warning": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, - "rc-steps": { - "version": "3.3.1", - "resolved": "http://registry.npm.taobao.org/rc-steps/download/rc-steps-3.3.1.tgz", - "integrity": "sha1-SHfiiXMx47/ba3ieiK6nj08V9zI=", - "requires": { - "babel-runtime": "^6.23.0", - "classnames": "^2.2.3", - "lodash": "^4.17.5", - "prop-types": "^15.5.7" - } - }, - "rc-switch": { - "version": "1.9.0", - "resolved": "http://registry.npm.taobao.org/rc-switch/download/rc-switch-1.9.0.tgz", - "integrity": "sha1-qyuHjycTxoE1ikUzkZdsm5WykPc=", - "requires": { - "classnames": "^2.2.1", - "prop-types": "^15.5.6", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-table": { - "version": "6.4.4", - "resolved": "http://registry.npm.taobao.org/rc-table/download/rc-table-6.4.4.tgz", - "integrity": "sha1-fOS4VuooFIRKAWQeyKzy1y7jpao=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "lodash": "^4.17.5", - "mini-store": "^2.0.0", - "prop-types": "^15.5.8", - "rc-util": "^4.0.4", - "react-lifecycles-compat": "^3.0.2", - "shallowequal": "^1.0.2", - "warning": "^3.0.0" - } - }, - "rc-tabs": { - "version": "9.6.3", - "resolved": "http://registry.npm.taobao.org/rc-tabs/download/rc-tabs-9.6.3.tgz", - "integrity": "sha1-XuAoFlIXafkuKNwDYKLrEhS1MHU=", - "requires": { - "babel-runtime": "6.x", - "classnames": "2.x", - "create-react-context": "0.2.2", - "lodash": "^4.17.5", - "prop-types": "15.x", - "raf": "^3.4.1", - "rc-hammerjs": "~0.6.0", - "rc-util": "^4.0.4", - "resize-observer-polyfill": "^1.5.1", - "warning": "^3.0.0" - }, - "dependencies": { - "raf": { - "version": "3.4.1", - "resolved": "http://registry.npm.taobao.org/raf/download/raf-3.4.1.tgz", - "integrity": "sha1-B0LpmkplUvRF1z4+4DKK8P8e3jk=", - "requires": { - "performance-now": "^2.1.0" - } - } - } - }, - "rc-time-picker": { - "version": "3.6.3", - "resolved": "http://registry.npm.taobao.org/rc-time-picker/download/rc-time-picker-3.6.3.tgz", - "integrity": "sha1-kV2R1oAWcknTJIcZ4IoxzqpcOwE=", - "requires": { - "classnames": "2.x", - "moment": "2.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.0" - } - }, - "rc-tooltip": { - "version": "3.7.3", - "resolved": "http://registry.npm.taobao.org/rc-tooltip/download/rc-tooltip-3.7.3.tgz", - "integrity": "sha1-KArsavyqROjf8EgPuv+eh/wArsw=", - "requires": { - "babel-runtime": "6.x", - "prop-types": "^15.5.8", - "rc-trigger": "^2.2.2" - } - }, "rc-tree": { "version": "1.15.2", "resolved": "http://registry.npm.taobao.org/rc-tree/download/rc-tree-1.15.2.tgz", @@ -10011,63 +9515,6 @@ } } }, - "rc-tree-select": { - "version": "2.6.2", - "resolved": "http://registry.npm.taobao.org/rc-tree-select/download/rc-tree-select-2.6.2.tgz", - "integrity": "sha1-eDuvvzq9D8ZFoHaXVjA47aYwLyk=", - "requires": { - "classnames": "^2.2.1", - "dom-scroll-into-view": "^1.2.1", - "prop-types": "^15.5.8", - "raf": "^3.4.0", - "rc-animate": "^3.0.0-rc.4", - "rc-tree": "~1.15.0", - "rc-trigger": "^3.0.0-rc.2", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4", - "shallowequal": "^1.0.2", - "warning": "^4.0.1" - }, - "dependencies": { - "rc-animate": { - "version": "3.0.0-rc.6", - "resolved": "http://registry.npm.taobao.org/rc-animate/download/rc-animate-3.0.0-rc.6.tgz", - "integrity": "sha1-BCiO76EY4MriFFNsipA/+qwbw/s=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5", - "component-classes": "^1.2.6", - "fbjs": "^0.8.16", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-util": "^4.5.0", - "react-lifecycles-compat": "^3.0.4" - } - }, - "rc-trigger": { - "version": "3.0.0-rc.3", - "resolved": "http://registry.npm.taobao.org/rc-trigger/download/rc-trigger-3.0.0-rc.3.tgz", - "integrity": "sha1-NYQt8WdNJTFeFCakSIKkyXZSJYs=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.6", - "prop-types": "15.x", - "raf": "^3.4.0", - "rc-align": "^2.4.1", - "rc-animate": "^3.0.0-rc.1", - "rc-util": "^4.4.0" - } - }, - "warning": { - "version": "4.0.3", - "resolved": "http://registry.npm.taobao.org/warning/download/warning-4.0.3.tgz", - "integrity": "sha1-Fungd+uKhtavfWSqHgX9hbRnjKM=", - "requires": { - "loose-envify": "^1.0.0" - } - } - } - }, "rc-trigger": { "version": "2.6.2", "resolved": "http://registry.npm.taobao.org/rc-trigger/download/rc-trigger-2.6.2.tgz", @@ -10181,17 +9628,6 @@ "text-table": "0.2.0" } }, - "react-dom": { - "version": "16.8.6", - "resolved": "http://registry.npm.taobao.org/react-dom/download/react-dom-16.8.6.tgz", - "integrity": "sha1-cdYwP2MeiwCX9WFl72CPBR/24Q8=", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "prop-types": "^15.6.2", - "scheduler": "^0.13.6" - } - }, "react-error-overlay": { "version": "4.0.1", "resolved": "http://registry.npm.taobao.org/react-error-overlay/download/react-error-overlay-4.0.1.tgz", @@ -10274,17 +9710,6 @@ } } }, - "react-lazy-load": { - "version": "3.0.13", - "resolved": "http://registry.npm.taobao.org/react-lazy-load/download/react-lazy-load-3.0.13.tgz", - "integrity": "sha1-OwqS0zbUPT8Nc8vm81sXBQsIuCQ=", - "requires": { - "eventlistener": "0.0.1", - "lodash.debounce": "^4.0.0", - "lodash.throttle": "^4.0.0", - "prop-types": "^15.5.8" - } - }, "react-lifecycles-compat": { "version": "3.0.4", "resolved": "http://registry.npm.taobao.org/react-lifecycles-compat/download/react-lifecycles-compat-3.0.4.tgz", @@ -10390,22 +9815,9 @@ "stifle": "^1.0.2" } }, - "react-slick": { - "version": "0.23.2", - "resolved": "http://registry.npm.taobao.org/react-slick/download/react-slick-0.23.2.tgz", - "integrity": "sha1-jYvbx3pmeOitNvUMMleMfA8cVPY=", - "requires": { - "classnames": "^2.2.5", - "enquire.js": "^2.1.6", - "json2mq": "^0.2.0", - "lodash.debounce": "^4.0.8", - "prettier": "^1.14.3", - "resize-observer-polyfill": "^1.5.0" - } - }, "react-transition-group": { "version": "1.2.1", - "resolved": "http://registry.npm.taobao.org/react-transition-group/download/react-transition-group-1.2.1.tgz", + "resolved": "https://registry.npm.taobao.org/react-transition-group/download/react-transition-group-1.2.1.tgz", "integrity": "sha1-4R9yslf5IbITIpp3TfRmEjRsfKY=", "requires": { "chain-function": "^1.0.0", @@ -11135,15 +10547,6 @@ "inherits": "^2.0.1" } }, - "rmc-feedback": { - "version": "2.0.0", - "resolved": "http://registry.npm.taobao.org/rmc-feedback/download/rmc-feedback-2.0.0.tgz", - "integrity": "sha1-y8bLOuY8emNe7w4l5PuvWsNm7qo=", - "requires": { - "babel-runtime": "6.x", - "classnames": "^2.2.5" - } - }, "run-async": { "version": "2.3.0", "resolved": "http://registry.npm.taobao.org/run-async/download/run-async-2.3.0.tgz", @@ -11225,15 +10628,6 @@ "resolved": "http://registry.npm.taobao.org/sax/download/sax-1.2.4.tgz", "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=" }, - "scheduler": { - "version": "0.13.6", - "resolved": "http://registry.npm.taobao.org/scheduler/download/scheduler-0.13.6.tgz", - "integrity": "sha1-RmpOwzJGezGpG5v3TlNHBy5M2Ik=", - "requires": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, "schema-utils": { "version": "0.3.0", "resolved": "http://registry.npm.taobao.org/schema-utils/download/schema-utils-0.3.0.tgz", @@ -11406,11 +10800,6 @@ "safe-buffer": "^5.0.1" } }, - "shallow-equal": { - "version": "1.1.0", - "resolved": "http://registry.npm.taobao.org/shallow-equal/download/shallow-equal-1.1.0.tgz", - "integrity": "sha1-zAIvAw3LoNHBmKv2WKPGx0Thcco=" - }, "shallowequal": { "version": "1.1.0", "resolved": "http://registry.npm.taobao.org/shallowequal/download/shallowequal-1.1.0.tgz", @@ -11934,11 +11323,6 @@ "resolved": "http://registry.npm.taobao.org/strict-uri-encode/download/strict-uri-encode-1.1.0.tgz", "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" }, - "string-convert": { - "version": "0.2.1", - "resolved": "http://registry.npm.taobao.org/string-convert/download/string-convert-0.2.1.tgz", - "integrity": "sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c=" - }, "string-length": { "version": "1.0.1", "resolved": "http://registry.npm.taobao.org/string-length/download/string-length-1.0.1.tgz", @@ -12248,11 +11632,6 @@ "resolved": "http://registry.npm.taobao.org/tiny-warning/download/tiny-warning-1.0.2.tgz", "integrity": "sha1-Hfrnce4aBDlr394no63OvGtkiyg=" }, - "tinycolor2": { - "version": "1.4.1", - "resolved": "http://registry.npm.taobao.org/tinycolor2/download/tinycolor2-1.4.1.tgz", - "integrity": "sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=" - }, "tmp": { "version": "0.0.33", "resolved": "http://registry.npm.taobao.org/tmp/download/tmp-0.0.33.tgz", @@ -12314,11 +11693,6 @@ } } }, - "toggle-selection": { - "version": "1.0.6", - "resolved": "http://registry.npm.taobao.org/toggle-selection/download/toggle-selection-1.0.6.tgz", - "integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI=" - }, "toposort": { "version": "1.0.7", "resolved": "http://registry.npm.taobao.org/toposort/download/toposort-1.0.7.tgz", diff --git a/public/react/package.json b/public/react/package.json index 84dec6d11..4d899935f 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -3,9 +3,9 @@ "version": "0.1.0", "private": true, "dependencies": { - "@icedesign/base": "^0.2.5", + "@icedesign/base": "^0.2.8", "@novnc/novnc": "^1.1.0", - "antd": "^3.20.1", + "antd": "^3.23.2", "array-flatten": "^2.1.2", "autoprefixer": "7.1.6", "axios": "^0.18.0", @@ -163,6 +163,8 @@ "babel-plugin-import": "^1.11.0", "concat": "^1.0.3", "happypack": "^5.0.1", + "node-sass": "^4.12.0", + "sass-loader": "^7.3.1", "webpack-bundle-analyzer": "^3.0.3", "webpack-parallel-uglify-plugin": "^1.1.0" } diff --git a/public/react/public/css/css_min_all.css b/public/react/public/css/css_min_all.css index e24882ec4..dc8331c69 100755 --- a/public/react/public/css/css_min_all.css +++ b/public/react/public/css/css_min_all.css @@ -1656,7 +1656,7 @@ html>body #ajax-indicator-base { position: fixed; } .fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:a 2s infinite linear}.fa-pulse{animation:a 1s infinite steps(8)}@keyframes a{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{-webkit-filter:none;filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-aws:before{content:"\f375"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blind:before{content:"\f29d"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-book:before{content:"\f02d"}.fa-book-open:before{content:"\f518"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-certificate:before{content:"\f0a3"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-credit-card:before{content:"\f09d"}.fa-crop:before{content:"\f125"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-deviantart:before{content:"\f1bd"}.fa-diagnoses:before{content:"\f470"}.fa-dice:before{content:"\f522"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-excel:before{content:"\f1c3"}.fa-file-image:before{content:"\f1c5"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fire:before{content:"\f06d"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-fulcrum:before{content:"\f50b"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-gift:before{content:"\f06b"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-martini:before{content:"\f000"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hashtag:before{content:"\f292"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-heart:before{content:"\f004"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-houzz:before{content:"\f27c"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-internet-explorer:before{content:"\f26b"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-joget:before{content:"\f3b7"}.fa-joomla:before{content:"\f1aa"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-meh:before{content:"\f11a"}.fa-memory:before{content:"\f538"}.fa-mercury:before{content:"\f223"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-moon:before{content:"\f186"}.fa-motorcycle:before{content:"\f21c"}.fa-mouse-pointer:before{content:"\f245"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-old-republic:before{content:"\f510"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-plane:before{content:"\f072"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poo:before{content:"\f2fe"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-r-project:before{content:"\f4f7"}.fa-random:before{content:"\f074"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-rendact:before{content:"\f3e4"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-retweet:before{content:"\f079"}.fa-ribbon:before{content:"\f4d6"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-rupee-sign:before{content:"\f156"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-search:before{content:"\f002"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shower:before{content:"\f2cc"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skull:before{content:"\f54c"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowflake:before{content:"\f2dc"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spinner:before{content:"\f110"}.fa-spotify:before{content:"\f1bc"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-star:before{content:"\f005"}.fa-star-half:before{content:"\f089"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toolbox:before{content:"\f552"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-train:before{content:"\f238"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-moving:before{content:"\f4df"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-glass:before{content:"\f4e3"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:Font Awesome\ 5 Brands;font-style:normal;font-weight:400;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:Font Awesome\ 5 Brands}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:Font Awesome\ 5 Free;font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:Font Awesome\ 5 Free}.fa,.fas{font-weight:900} /*! Editor.md v1.5.0 | editormd.min.css | Open source online markdown editor. | MIT License | By: Pandao | https://github.com/pandao/editor.md | 2015-06-09 */ -@charset "UTF-8";/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */.fa-ul,.markdown-body .task-list-item,li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}.editormd-form br,.markdown-body hr:after{clear:both}.editormd{width:90%;height:640px;margin:0 auto 15px;text-align:left;overflow:hidden;position:relative;border:1px solid #ddd;font-family:"微软雅黑", "Meiryo UI","Microsoft YaHei","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,monospace,Tahoma,STXihei,"华文细黑",STHeiti,"Helvetica Neue","Droid Sans","wenquanyi micro hei",FreeSans,Arimo,Arial,SimSun,"宋体",Heiti,"黑体",sans-serif}.editormd *,.editormd :after,.editormd :before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd a{text-decoration:none}.editormd img{border:none;vertical-align:middle}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea,.editormd>textarea{width:0;height:0;outline:0;resize:none}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea{display:none}.editormd button,.editormd input[type=text],.editormd input[type=button],.editormd input[type=submit],.editormd select,.editormd textarea{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none}.editormd ::-webkit-scrollbar{height:10px;width:7px;background:rgba(0,0,0,.1)}.editormd ::-webkit-scrollbar:hover{background:rgba(0,0,0,.2)}.editormd ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px}.editormd ::-webkit-scrollbar-thumb:hover{-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-ms-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);background-color:rgba(0,0,0,.4)}.editormd-user-unselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.editormd-toolbar{width:100%;min-height:37px;background:#fff;display:none;position:absolute;top:0;left:0;z-index:10;border-bottom:1px solid #ddd}.editormd-toolbar-container{padding:0 8px;min-height:35px;-o-user-select:none;user-select:none}.editormd-toolbar-container,.markdown-body .octicon{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.editormd-menu,.markdown-body ol,.markdown-body td,.markdown-body th,.markdown-body ul{padding:0}.editormd-menu{margin:0;list-style:none}.editormd-menu>li{margin:0;padding:5px 1px;display:inline-block;position:relative}.editormd-menu>li.divider{display:inline-block;text-indent:-9999px;margin:0 5px;height:65%;border-right:1px solid #ddd}.editormd-menu>li>a{outline:0;color:#666;display:inline-block;min-width:24px;font-size:16px;text-decoration:none;text-align:center;-webkit-border-radius:2px;-moz-border-radius:2px;-ms-border-radius:2px;-o-border-radius:2px;border-radius:2px;border:1px solid #fff;transition:all 300ms ease-out}.editormd-dropdown-menu>li>a:hover,.editormd-menu>li>a{-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out}.editormd-menu>li>a.active,.editormd-menu>li>a:hover{border:1px solid #ddd;background:#eee}.editormd-menu>li>a>.fa{text-align:center;display:block;padding:5px}.editormd-menu>li>a>.editormd-bold{padding:5px 2px;display:inline-block;font-weight:700}.editormd-menu>li:hover .editormd-dropdown-menu{display:block}.editormd-menu>li+li>a{margin-left:3px}.editormd-dropdown-menu{display:none;background:#fff;border:1px solid #ddd;width:148px;list-style:none;position:absolute;top:33px;left:0;z-index:100;-webkit-box-shadow:1px 2px 6px rgba(0,0,0,.15);-moz-box-shadow:1px 2px 6px rgba(0,0,0,.15);-ms-box-shadow:1px 2px 6px rgba(0,0,0,.15);-o-box-shadow:1px 2px 6px rgba(0,0,0,.15);box-shadow:1px 2px 6px rgba(0,0,0,.15)}.editormd-dropdown-menu:after,.editormd-dropdown-menu:before{width:0;height:0;display:block;content:"";position:absolute;top:-11px;left:8px;border:5px solid transparent}.editormd-dropdown-menu:before{border-bottom-color:#ccc}.editormd-dropdown-menu:after{border-bottom-color:#fff;top:-10px}.editormd-dropdown-menu>li>a{color:#666;display:block;text-decoration:none;padding:8px 10px}.editormd-dropdown-menu>li>a:hover{background:#f6f6f6;transition:all 300ms ease-out}.editormd-dropdown-menu>li+li{border-top:1px solid #ddd}.editormd-container{margin:0;width:100%;height:100%;overflow:hidden;padding:35px 0 0;position:relative;background:#fff;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd-dialog{color:#666;position:fixed;z-index:99999;display:none;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);-moz-box-shadow:0 0 10px rgba(0,0,0,.3);-ms-box-shadow:0 0 10px rgba(0,0,0,.3);-o-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);background:#fff;font-size:14px}.editormd-dialog-container{position:relative;padding:20px;line-height:1.4}.editormd-dialog-container h1{font-size:24px;margin-bottom:10px}.editormd-dialog-container h1 .fa{color:#2C7EEA;padding-right:5px}.editormd-dialog-container h1 small{padding-left:5px;font-weight:400;font-size:12px;color:#999}.editormd-dialog-container select{color:#999;padding:3px 8px;border:1px solid #ddd}.editormd-dialog-close{position:absolute;top:12px;right:15px;font-size:18px;color:#ccc;-webkit-transition:color 300ms ease-out;-moz-transition:color 300ms ease-out;transition:color 300ms ease-out}.editormd-dialog-close:hover{color:#999}.editormd-dialog-header{padding:11px 20px;border-bottom:1px solid #eee;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-header:hover{background:#f6f6f6}.editormd-dialog-title{font-size:14px}.editormd-dialog-footer{padding:10px 0 0;text-align:right}.editormd-dialog-info{width:420px}.editormd-dialog-info h1{font-weight:400}.editormd-dialog-info .editormd-dialog-container{padding:20px 25px 25px}.editormd-dialog-info .editormd-dialog-close{top:10px;right:10px}.editormd-dialog-info .hover-link:hover,.editormd-dialog-info p>a{color:#2196F3}.editormd-dialog-info .hover-link{color:#666}.editormd-dialog-info a .fa-external-link{display:none}.editormd-dialog-info a:hover{color:#2196F3}.editormd-dialog-info a:hover .fa-external-link{display:inline-block}.editormd-container-mask,.editormd-dialog-mask,.editormd-mask{display:none;width:100%;height:100%;position:absolute;top:0;left:0}.editormd-dialog-mask-bg,.editormd-mask{background:#fff;opacity:.5;filter:alpha(opacity=50)}.editormd-mask{position:fixed;background:#000;opacity:.2;filter:alpha(opacity=20);z-index:99998}.editormd-container-mask,.editormd-dialog-mask-con{background:url(../images/loading.gif)center center no-repeat;-webkit-background-size:32px 32px;-moz-background-size:32px 32px;-o-background-size:32px 32px;background-size:32px 32px}.editormd-container-mask{z-index:20;display:block;background-color:#fff}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@2x.gif)}}@media only screen and (-webkit-min-device-pixel-ratio:3),only screen and (min-device-pixel-ratio:3){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@3x.gif)}}.editormd-code-block-dialog textarea,.editormd-preformatted-text-dialog textarea{width:100%;height:400px;margin-bottom:6px;overflow:auto;border:1px solid #eee;background:#fff;padding:15px;resize:none}.editormd-code-toolbar{color:#999;font-size:14px;margin:-5px 0 10px}.editormd-grid-table{width:99%;display:table;border:1px solid #ddd;border-collapse:collapse}.editormd-grid-table-row{width:100%;display:table-row}.editormd-grid-table-row a{font-size:1.4em;width:5%;height:36px;color:#999;text-align:center;display:table-cell;vertical-align:middle;border:1px solid #ddd;text-decoration:none;-webkit-transition:background-color 300ms ease-out,color 100ms ease-in;-moz-transition:background-color 300ms ease-out,color 100ms ease-in;transition:background-color 300ms ease-out,color 100ms ease-in}.editormd-grid-table-row a.selected{color:#666;background-color:#eee}.editormd-grid-table-row a:hover{color:#777;background-color:#f6f6f6}.editormd-tab-head{list-style:none;border-bottom:1px solid #ddd}.editormd-tab-head li{display:inline-block}.editormd-tab-head li a{color:#999;display:block;padding:6px 12px 5px;text-align:center;text-decoration:none;margin-bottom:-1px;border:1px solid #ddd;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;-ms-border-top-left-radius:3px;-o-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;-ms-border-top-right-radius:3px;-o-border-top-right-radius:3px;border-top-right-radius:3px;background:#f6f6f6;-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out;transition:all 300ms ease-out}.editormd-tab-head li a:hover{color:#666;background:#eee}.editormd-tab-head li.active a{color:#666;background:#fff;border-bottom-color:#fff}.editormd-tab-head li+li{margin-left:3px}.editormd-tab-box{padding:20px 0}.editormd-form{color:#666}.editormd-form label{float:left;display:block;width:75px;text-align:left;padding:7px 0 15px 5px;margin:0 0 2px;font-weight:400}.editormd-form iframe{display:none}.editormd-form input:focus{outline:0}.editormd-form input[type=text],.editormd-form input[type=number]{color:#999;padding:4px;border:1px solid #ddd}.editormd-form input[type=number]{width:40px;display:inline-block;padding:6px 8px}.editormd-form input[type=text]{display:inline-block;width:264px}.editormd-form .fa-btns{display:inline-block}.editormd-form .fa-btns a{color:#999;padding:7px 10px 0 0;display:inline-block;text-decoration:none;text-align:center}.editormd-form .fa-btns .fa{font-size:1.3em}.editormd-form .fa-btns label{float:none;display:inline-block;width:auto;text-align:left;padding:0 0 0 5px;cursor:pointer}.fa-fw,.fa-li{text-align:center}.editormd-dialog-container .editormd-btn,.editormd-dialog-container button,.editormd-dialog-container input[type=submit],.editormd-dialog-footer .editormd-btn,.editormd-dialog-footer button,.editormd-dialog-footer input[type=submit],.editormd-form .editormd-btn,.editormd-form button,.editormd-form input[type=submit]{color:#666;min-width:75px;cursor:pointer;background:#fff;padding:3px 10px;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-container .editormd-btn:hover,.editormd-dialog-container button:hover,.editormd-dialog-container input[type=submit]:hover,.editormd-dialog-footer .editormd-btn:hover,.editormd-dialog-footer button:hover,.editormd-dialog-footer input[type=submit]:hover,.editormd-form .editormd-btn:hover,.editormd-form button:hover,.editormd-form input[type=submit]:hover{background:#eee}.editormd-dialog-container .editormd-btn+.editormd-btn,.editormd-dialog-footer .editormd-btn+.editormd-btn,.editormd-form .editormd-btn+.editormd-btn{margin-left:8px}.editormd-file-input{width:75px;height:32px;margin-left:8px;position:relative;display:inline-block}.editormd-file-input input[type=file]{width:75px;height:32px;opacity:0;cursor:pointer;background:#000;display:inline-block;position:absolute;top:0;right:0}.editormd-file-input input[type=file]::-webkit-file-upload-button{visibility:hidden}.editormd-file-input:hover input[type=submit]{background:#eee}.editormd .CodeMirror,.editormd-preview{display:inline-block;width:50%;height:100%;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0}.editormd-preview{position:absolute;top:35px;right:0;overflow:auto;line-height:1.6;display:none;background:#fff}.fa,.fa-stack{display:inline-block}.editormd .CodeMirror{z-index:10;float:left;border-right:1px solid #ddd;font-size:14px;font-family:"YaHei Consolas Hybrid",Consolas,"微软雅黑","Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,courier,monospace;line-height:1.6;margin-top:35px}.editormd .CodeMirror pre{font-size:14px;padding:0 12px}.editormd .CodeMirror-linenumbers{padding:0 5px}.editormd .CodeMirror-focused .CodeMirror-selected,.editormd .CodeMirror-selected{background:#70B7FF}.editormd .CodeMirror,.editormd .CodeMirror-scroll,.editormd .editormd-preview{-webkit-overflow-scrolling:touch}.editormd .styled-background{background-color:#ff7}.editormd .CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.editormd .CodeMirror-empty.CodeMirror-focused{outline:0}.editormd .CodeMirror pre.CodeMirror-placeholder{color:#999}.editormd .cm-trailingspace{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);background-position:bottom left;background-repeat:repeat-x}.editormd .cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=)right no-repeat}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ +@charset "UTF-8";/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */.fa-ul,.markdown-body .task-list-item,li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}.editormd-form br,.markdown-body hr:after{clear:both}.editormd{width:90%;height:640px;margin:0 auto 15px;text-align:left;overflow:hidden;position:relative;border:1px solid #ddd;font-family:"微软雅黑", "Meiryo UI","Microsoft YaHei","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,monospace,Tahoma,STXihei,"华文细黑",STHeiti,"Helvetica Neue","Droid Sans","wenquanyi micro hei",FreeSans,Arimo,Arial,SimSun,"宋体",Heiti,"黑体",sans-serif}.editormd *,.editormd :after,.editormd :before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd a{text-decoration:none}.editormd img{border:none;vertical-align:middle}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea,.editormd>textarea{width:0;height:0;outline:0;resize:none}.editormd .editormd-html-textarea,.editormd .editormd-markdown-textarea{display:none}.editormd button,.editormd input[type=text],.editormd input[type=button],.editormd input[type=submit],.editormd select,.editormd textarea{-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;appearance:none}.editormd ::-webkit-scrollbar{height:10px;width:7px;background:rgba(0,0,0,.1)}.editormd ::-webkit-scrollbar:hover{background:rgba(0,0,0,.2)}.editormd ::-webkit-scrollbar-thumb{background:rgba(0,0,0,.3);-webkit-border-radius:6px;-moz-border-radius:6px;-ms-border-radius:6px;-o-border-radius:6px;border-radius:6px}.editormd ::-webkit-scrollbar-thumb:hover{-webkit-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-moz-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-ms-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);-o-box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);box-shadow:inset 1px 1px 1px rgba(0,0,0,.25);background-color:rgba(0,0,0,.4)}.editormd-user-unselect{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.editormd-toolbar{width:100%;min-height:37px;background:#fff;display:none;position:absolute;top:0;left:0;z-index:10;border-bottom:1px solid #ddd}.editormd-toolbar-container{padding:0 8px;min-height:35px;-o-user-select:none;user-select:none}.editormd-toolbar-container,.markdown-body .octicon{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.editormd-menu,.markdown-body ol,.markdown-body td,.markdown-body th,.markdown-body ul{padding:0}.editormd-menu{margin:0;list-style:none}.editormd-menu>li{margin:0;padding:5px 1px;display:inline-block;position:relative}.editormd-menu>li.divider{display:inline-block;text-indent:-9999px;margin:0 5px;height:65%;border-right:1px solid #ddd}.editormd-menu>li>a{outline:0;color:#666;display:inline-block;min-width:24px;font-size:16px;text-decoration:none;text-align:center;-webkit-border-radius:2px;-moz-border-radius:2px;-ms-border-radius:2px;-o-border-radius:2px;border-radius:2px;border:1px solid #fff;transition:all 300ms ease-out}.editormd-dropdown-menu>li>a:hover,.editormd-menu>li>a{-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out}.editormd-menu>li>a.active,.editormd-menu>li>a:hover{border:1px solid #ddd;background:#eee}.editormd-menu>li>a>.fa{text-align:center;display:block;padding:5px}.editormd-menu>li>a>.editormd-bold{padding:5px 2px;display:inline-block;font-weight:700}.editormd-menu>li:hover .editormd-dropdown-menu{display:block}.editormd-menu>li+li>a{margin-left:3px}.editormd-dropdown-menu{display:none;background:#fff;border:1px solid #ddd;width:148px;list-style:none;position:absolute;top:33px;left:0;z-index:100;-webkit-box-shadow:1px 2px 6px rgba(0,0,0,.15);-moz-box-shadow:1px 2px 6px rgba(0,0,0,.15);-ms-box-shadow:1px 2px 6px rgba(0,0,0,.15);-o-box-shadow:1px 2px 6px rgba(0,0,0,.15);box-shadow:1px 2px 6px rgba(0,0,0,.15)}.editormd-dropdown-menu:after,.editormd-dropdown-menu:before{width:0;height:0;display:block;content:"";position:absolute;top:-11px;left:8px;border:5px solid transparent}.editormd-dropdown-menu:before{border-bottom-color:#ccc}.editormd-dropdown-menu:after{border-bottom-color:#fff;top:-10px}.editormd-dropdown-menu>li>a{color:#666;display:block;text-decoration:none;padding:8px 10px}.editormd-dropdown-menu>li>a:hover{background:#f6f6f6;transition:all 300ms ease-out}.editormd-dropdown-menu>li+li{border-top:1px solid #ddd}.editormd-container{margin:0;width:100%;height:100%;overflow:hidden;padding:35px 0 0;position:relative;background:#fff;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.editormd-dialog{color:#666;position:fixed;z-index:99999;display:none;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);-moz-box-shadow:0 0 10px rgba(0,0,0,.3);-ms-box-shadow:0 0 10px rgba(0,0,0,.3);-o-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);background:#fff;font-size:14px}.editormd-dialog-container{position:relative;padding:20px;line-height:1.4}.editormd-dialog-container h1{font-size:24px;margin-bottom:10px}.editormd-dialog-container h1 .fa{color:#2C7EEA;padding-right:5px}.editormd-dialog-container h1 small{padding-left:5px;font-weight:400;font-size:12px;color:#999}.editormd-dialog-container select{color:#999;padding:3px 8px;border:1px solid #ddd}.editormd-dialog-close{position:absolute;top:12px;right:15px;font-size:18px;color:#ccc;-webkit-transition:color 300ms ease-out;-moz-transition:color 300ms ease-out;transition:color 300ms ease-out}.editormd-dialog-close:hover{color:#999}.editormd-dialog-header{padding:11px 20px;border-bottom:1px solid #eee;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-header:hover{background:#f6f6f6}.editormd-dialog-title{font-size:14px}.editormd-dialog-footer{padding:10px 0 0;text-align:right}.editormd-dialog-info{width:420px}.editormd-dialog-info h1{font-weight:400}.editormd-dialog-info .editormd-dialog-container{padding:20px 25px 25px}.editormd-dialog-info .editormd-dialog-close{top:10px;right:10px}.editormd-dialog-info .hover-link:hover,.editormd-dialog-info p>a{color:#2196F3}.editormd-dialog-info .hover-link{color:#666}.editormd-dialog-info a .fa-external-link{display:none}.editormd-dialog-info a:hover{color:#2196F3}.editormd-dialog-info a:hover .fa-external-link{display:inline-block}.editormd-container-mask,.editormd-dialog-mask,.editormd-mask{display:none;width:100%;height:100%;position:absolute;top:0;left:0}.editormd-dialog-mask-bg,.editormd-mask{background:#fff;opacity:.5;filter:alpha(opacity=50)}.editormd-mask{position:fixed;background:#000;opacity:.2;filter:alpha(opacity=20);z-index:99998}.editormd-container-mask,.editormd-dialog-mask-con{background:url(../images/loading.gif)center center no-repeat;-webkit-background-size:32px 32px;-moz-background-size:32px 32px;-o-background-size:32px 32px;background-size:32px 32px}.editormd-container-mask{z-index:20;display:block;background-color:#fff}@media only screen and (-webkit-min-device-pixel-ratio:2),only screen and (min-device-pixel-ratio:2){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@2x.gif)}}@media only screen and (-webkit-min-device-pixel-ratio:3),only screen and (min-device-pixel-ratio:3){.editormd-container-mask,.editormd-dialog-mask-con{background-image:url(../images/loading@3x.gif)}}.editormd-code-block-dialog textarea,.editormd-preformatted-text-dialog textarea{width:100%;height:400px;margin-bottom:6px;overflow:auto;border:1px solid #eee;background:#fff;padding:15px;resize:none}.editormd-code-toolbar{color:#999;font-size:14px;margin:-5px 0 10px}.editormd-grid-table{width:99%;display:table;border:1px solid #ddd;border-collapse:collapse}.editormd-grid-table-row{width:100%;display:table-row}.editormd-grid-table-row a{font-size:1.4em;width:5%;height:36px;color:#999;text-align:center;display:table-cell;vertical-align:middle;border:1px solid #ddd;text-decoration:none;-webkit-transition:background-color 300ms ease-out,color 100ms ease-in;-moz-transition:background-color 300ms ease-out,color 100ms ease-in;transition:background-color 300ms ease-out,color 100ms ease-in}.editormd-grid-table-row a.selected{color:#666;background-color:#eee}.editormd-grid-table-row a:hover{color:#777;background-color:#f6f6f6}.editormd-tab-head{list-style:none;border-bottom:1px solid #ddd}.editormd-tab-head li{display:inline-block}.editormd-tab-head li a{color:#999;display:block;padding:6px 12px 5px;text-align:center;text-decoration:none;margin-bottom:-1px;border:1px solid #ddd;-webkit-border-top-left-radius:3px;-moz-border-top-left-radius:3px;-ms-border-top-left-radius:3px;-o-border-top-left-radius:3px;border-top-left-radius:3px;-webkit-border-top-right-radius:3px;-moz-border-top-right-radius:3px;-ms-border-top-right-radius:3px;-o-border-top-right-radius:3px;border-top-right-radius:3px;background:#f6f6f6;-webkit-transition:all 300ms ease-out;-moz-transition:all 300ms ease-out;transition:all 300ms ease-out}.editormd-tab-head li a:hover{color:#666;background:#eee}.editormd-tab-head li.active a{color:#666;background:#fff;border-bottom-color:#fff}.editormd-tab-head li+li{margin-left:3px}.editormd-tab-box{padding:20px 0}.editormd-form{color:#666}.editormd-form label{float:left;display:block;width:75px;text-align:left;padding:7px 0 15px 5px;margin:0 0 2px;font-weight:400}.editormd-form iframe{display:none}.editormd-form input:focus{outline:0}.editormd-form input[type=text],.editormd-form input[type=number]{color:#999;padding:4px;border:1px solid #ddd}.editormd-form input[type=number]{width:40px;display:inline-block;padding:6px 8px}.editormd-form input[type=text]{display:inline-block;width:264px}.editormd-form .fa-btns{display:inline-block}.editormd-form .fa-btns a{color:#999;padding:7px 10px 0 0;display:inline-block;text-decoration:none;text-align:center}.editormd-form .fa-btns .fa{font-size:1.3em}.editormd-form .fa-btns label{float:none;display:inline-block;width:auto;text-align:left;padding:0 0 0 5px;cursor:pointer}.fa-fw,.fa-li{text-align:center}.editormd-dialog-container .editormd-btn,.editormd-dialog-container button,.editormd-dialog-container input[type=submit],.editormd-dialog-footer .editormd-btn,.editormd-dialog-footer button,.editormd-dialog-footer input[type=submit],.editormd-form .editormd-btn,.editormd-form button,.editormd-form input[type=submit]{color:#666;min-width:75px;cursor:pointer;background:#fff;padding:3px 10px;border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;-ms-border-radius:3px;-o-border-radius:3px;border-radius:3px;-webkit-transition:background 300ms ease-out;-moz-transition:background 300ms ease-out;transition:background 300ms ease-out}.editormd-dialog-container .editormd-btn:hover,.editormd-dialog-container button:hover,.editormd-dialog-container input[type=submit]:hover,.editormd-dialog-footer .editormd-btn:hover,.editormd-dialog-footer button:hover,.editormd-dialog-footer input[type=submit]:hover,.editormd-form .editormd-btn:hover,.editormd-form button:hover,.editormd-form input[type=submit]:hover{background:#eee}.editormd-dialog-container .editormd-btn+.editormd-btn,.editormd-dialog-footer .editormd-btn+.editormd-btn,.editormd-form .editormd-btn+.editormd-btn{margin-left:8px}.editormd-file-input{width:75px;height:32px;margin-left:8px;position:relative;display:inline-block}.editormd-file-input input[type=file]{width:75px;height:32px;opacity:0;cursor:pointer;background:#000;display:inline-block;position:absolute;top:0;right:0}.editormd-file-input input[type=file]::-webkit-file-upload-button{visibility:hidden}.editormd-file-input:hover input[type=submit]{background:#eee}.editormd .CodeMirror,.editormd-preview{display:inline-block;width:50%;height:100%;vertical-align:top;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0}.editormd-preview{position:absolute;top:35px;right:0;overflow:auto;line-height:1.6;display:none;background:#fff}.fa,.fa-stack{display:inline-block}.editormd .CodeMirror{z-index:10;float:left;border-right:1px solid #ddd;font-size:14px;font-family:"YaHei Consolas Hybrid",Consolas,"微软雅黑","Meiryo UI","Malgun Gothic","Segoe UI","Trebuchet MS",Helvetica,Monaco,courier,monospace;line-height:1.6;margin-top:35px}.editormd .CodeMirror pre{font-size:14px!important;padding:0 12px}.editormd .CodeMirror-linenumbers{padding:0 5px}.editormd .CodeMirror-focused .CodeMirror-selected,.editormd .CodeMirror-selected{background:#70B7FF}.editormd .CodeMirror,.editormd .CodeMirror-scroll,.editormd .editormd-preview{-webkit-overflow-scrolling:touch}.editormd .styled-background{background-color:#ff7}.editormd .CodeMirror-focused .cm-matchhighlight{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);background-position:bottom;background-repeat:repeat-x}.editormd .CodeMirror-empty.CodeMirror-focused{outline:0}.editormd .CodeMirror pre.CodeMirror-placeholder{color:#999}.editormd .cm-trailingspace{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3QUXCToH00Y1UgAAACFJREFUCNdjPMDBUc/AwNDAAAFMTAwMDA0OP34wQgX/AQBYgwYEx4f9lQAAAABJRU5ErkJggg==);background-position:bottom left;background-repeat:repeat-x}.editormd .cm-tab{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAMCAYAAAAkuj5RAAAAAXNSR0IArs4c6QAAAGFJREFUSMft1LsRQFAQheHPowAKoACx3IgEKtaEHujDjORSgWTH/ZOdnZOcM/sgk/kFFWY0qV8foQwS4MKBCS3qR6ixBJvElOobYAtivseIE120FaowJPN75GMu8j/LfMwNjh4HUpwg4LUAAAAASUVORK5CYII=)right no-repeat}/*! prefixes.scss v0.1.0 | Author: Pandao | https://github.com/pandao/prefixes.scss | MIT license | Copyright (c) 2015 */ /* 重置掉些样式 */ .tpi_content p, .tpi_content dl, .tpi_content ol, .tpi_content ul, diff --git a/public/react/public/index.html b/public/react/public/index.html index 166760eab..a2d09dedc 100755 --- a/public/react/public/index.html +++ b/public/react/public/index.html @@ -5,10 +5,9 @@ - + + +