diff --git a/app/assets/javascripts/forums.js b/app/assets/javascripts/forums.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/forums.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/javascripts/memos.js b/app/assets/javascripts/memos.js new file mode 100644 index 000000000..dee720fac --- /dev/null +++ b/app/assets/javascripts/memos.js @@ -0,0 +1,2 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. diff --git a/app/assets/stylesheets/forums.scss b/app/assets/stylesheets/forums.scss new file mode 100644 index 000000000..fafd631e1 --- /dev/null +++ b/app/assets/stylesheets/forums.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the forums controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f01ad4b6b..c76ca51a7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -38,6 +38,7 @@ class ApplicationController < ActionController::Base def user_course_identity @user_course_identity = current_user.course_identity(@course) if @user_course_identity > Course::STUDENT && @course.is_public == 0 + tip_exception(401, "..") unless User.current.logged? tip_exception(409, "您没有权限进入") end uid_logger("###############user_course_identity:#{@user_course_identity}") @@ -582,4 +583,8 @@ class ApplicationController < ActionController::Base def render_parameter_missing render json: { status: -1, message: '参数缺失' } end + + def set_export_cookies + cookies[:fileDownload] = true + end end diff --git a/app/controllers/concerns/git_helper.rb b/app/controllers/concerns/git_helper.rb index 65ebd4074..d77e1c3f6 100644 --- a/app/controllers/concerns/git_helper.rb +++ b/app/controllers/concerns/git_helper.rb @@ -48,7 +48,7 @@ module GitHelper def project_fork(container, original_rep_path, username) raise Educoder::TipException.new("fork源路径为空,fork失败!") if original_rep_path.blank? # 将要生成的仓库名字 - new_repo_name = "#{username}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}" + new_repo_name = "#{username.try(:strip)}/#{container.try(:identifier)}#{ Time.now.strftime("%Y%m%d%H%M%S")}" uid_logger("start fork container: repo_name is #{new_repo_name}") GitService.fork_repository(repo_path: original_rep_path, fork_repository_path: (new_repo_name + ".git")) container.update_attributes!(:repo_name => new_repo_name) diff --git a/app/controllers/concerns/paginate_helper.rb b/app/controllers/concerns/paginate_helper.rb index 34740eb5d..bbe84a348 100644 --- a/app/controllers/concerns/paginate_helper.rb +++ b/app/controllers/concerns/paginate_helper.rb @@ -1,7 +1,7 @@ module PaginateHelper def paginate(objs, **opts) page = params[:page].to_i <= 0 ? 1 : params[:page].to_i - per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : opts[:per_page] || 20 + 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) end diff --git a/app/controllers/courses_controller.rb b/app/controllers/courses_controller.rb index bdb367111..abc3e4856 100644 --- a/app/controllers/courses_controller.rb +++ b/app/controllers/courses_controller.rb @@ -1027,10 +1027,13 @@ class CoursesController < ApplicationController tip_exception(403,"无权限操作") elsif @all_members.size == 0 normal_status(-1,"课堂暂时没有学生") + elsif params[:export].present? && params[:export] + normal_status(0,"正在下载中") else + set_export_cookies member_to_xlsx(@course, @all_members, @c_homeworks, @c_exercises, @c_tasks) - filename_ = "#{current_user.real_name}_#{@course.name}_全部成绩" - render xlsx: "#{format_sheet_name filename_.strip.first(30)}",template: "courses/export_member_scores_excel.xlsx.axlsx", + filename_ = "#{current_user.real_name}_#{@course.name}_全部成绩_#{Time.now.strftime('%Y%m%d_%H%M%S')}" + render xlsx: "#{format_sheet_name filename_.strip}",template: "courses/export_member_scores_excel.xlsx.axlsx", locals: {course_info:@course_info, activity_level:@user_activity_level, course_scores:@course_user_scores,shixun_works:@shixun_work_arrays, common_works:@common_work_arrays,group_works:@group_work_arrays,task_works:@task_work_arrays, diff --git a/app/controllers/exercises_controller.rb b/app/controllers/exercises_controller.rb index 03c943f8d..6f121db5f 100644 --- a/app/controllers/exercises_controller.rb +++ b/app/controllers/exercises_controller.rb @@ -1256,13 +1256,16 @@ class ExercisesController < ApplicationController normal_status(-1,"试卷未发布") elsif (@exercise_users_size == 0) || ( @export_ex_users&.exercise_user_committed.size == 0) normal_status(-1,"暂无用户提交") + elsif params[:export].present? && params[:export] + normal_status(0,"正在下载中") else respond_to do |format| format.xlsx{ + set_export_cookies get_export_users(@exercise,@course,@export_ex_users) exercise_export_name_ = "#{current_user.real_name}_#{@course.name}_#{@exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" - render xlsx: "#{exercise_export_name_.strip.first(30)}",template: "exercises/exercise_lists.xlsx.axlsx",locals: {table_columns:@table_columns,exercise_users:@user_columns} + render xlsx: "#{exercise_export_name_.strip}",template: "exercises/exercise_lists.xlsx.axlsx",locals: {table_columns:@table_columns,exercise_users:@user_columns} } end end @@ -1281,7 +1284,12 @@ class ExercisesController < ApplicationController @exercise_questions = @exercise.exercise_questions.includes(:exercise_choices).order("question_number ASC") filename_ = "#{@exercise.user.real_name}_#{@course.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf" stylesheets = "#{Rails.root}/app/templates/exercise_export/exercise_export.css" - render pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + set_export_cookies + render pdf: 'exercise_export/blank_exercise', filename: filename_, stylesheets: stylesheets + end end #空白试卷预览页面,仅供测试使用,无其他任何用途 diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb new file mode 100644 index 000000000..82573fdd0 --- /dev/null +++ b/app/controllers/forums_controller.rb @@ -0,0 +1,2 @@ +class ForumsController < ApplicationController +end diff --git a/app/controllers/games_controller.rb b/app/controllers/games_controller.rb index b2de6dcad..b3b062c1a 100644 --- a/app/controllers/games_controller.rb +++ b/app/controllers/games_controller.rb @@ -116,10 +116,11 @@ class GamesController < ApplicationController @qrcode_str = Base64.encode64( qr.to_img.resize(400,400).to_s ) else - @type = "image" #conv = Iconv.new("GBK", "utf-8") @game_challenge = @game.challenge type = @game_challenge.show_type + @type = shixun_show_type type + workspace_path = @game.try(:picture_path) @answer_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.expect_picture_path}" @user_path = "#{Rails.root}/#{workspace_path}/#{@game_challenge.picture_path}" diff --git a/app/controllers/graduation_tasks_controller.rb b/app/controllers/graduation_tasks_controller.rb index ab99e8d86..0885eeae2 100644 --- a/app/controllers/graduation_tasks_controller.rb +++ b/app/controllers/graduation_tasks_controller.rb @@ -132,12 +132,14 @@ class GraduationTasksController < ApplicationController tip_exception(403, "无权限操作") elsif complete_works == 0 normal_status(-1,"暂无用户提交") + elsif params[:export].present? && params[:export] + normal_status(0,"正在下载中") else respond_to do |format| format.xlsx{ graduation_work_to_xlsx(@work_excel,@task,current_user) task_export_name_ = "#{current_user.real_name}_#{@course.name}_#{@task.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" - render xlsx: "#{task_export_name_.strip.first(30)}",template: "graduation_tasks/tasks_list.xlsx.axlsx",locals: {table_columns:@head_cells_column, task_users:@task_cells_column} + render xlsx: "#{task_export_name_.strip}",template: "graduation_tasks/tasks_list.xlsx.axlsx",locals: {table_columns:@head_cells_column, task_users:@task_cells_column} } end end @@ -148,12 +150,17 @@ class GraduationTasksController < ApplicationController zip_works = @work_excel.where("work_status > 0") status = checkfileSize(zip_works) if status == 0 - respond_to do |format| - format.zip{ - zipfile = zip_homework_common @task, zip_works - file = decode64(zipfile[0][:base64file]) - send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' - } + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + respond_to do |format| + format.zip{ + set_export_cookies + zipfile = zip_homework_common @task, zip_works + file = decode64(zipfile[0][:base64file]) + send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' + } + end end else normal_status(status,status == -2 ? "500M" : "无附件可下载") diff --git a/app/controllers/graduation_topics_controller.rb b/app/controllers/graduation_topics_controller.rb index 754b472c5..bd93401f3 100644 --- a/app/controllers/graduation_topics_controller.rb +++ b/app/controllers/graduation_topics_controller.rb @@ -271,7 +271,12 @@ class GraduationTopicsController < ApplicationController students = course.students.joins(user: :user_extension).order("user_extensions.student_id") graduation_topic_to_xlsx(students,course) topic_export_name_ = "#{current_user.real_name}_#{course.name}_毕设选题_#{Time.now.strftime('%Y%m%d_%H%M%S')}" - render xlsx: "#{topic_export_name_.strip.first(30)}",template: "graduation_topics/export.xlsx.axlsx",locals: {table_columns:@topic_head_cells,topic_users:@topic_body_cells} + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + set_export_cookies + render xlsx: "#{topic_export_name_.strip}",template: "graduation_topics/export.xlsx.axlsx",locals: {table_columns:@topic_head_cells,topic_users:@topic_body_cells} + end rescue Exception => e uid_logger(e.message) missing_template diff --git a/app/controllers/homework_commons_controller.rb b/app/controllers/homework_commons_controller.rb index 29f270a34..f7906ecda 100644 --- a/app/controllers/homework_commons_controller.rb +++ b/app/controllers/homework_commons_controller.rb @@ -207,12 +207,15 @@ class HomeworkCommonsController < ApplicationController tip_exception(403, "无权限操作") elsif @work_excel.blank? || @work_excel.size == 0 normal_status(-1,"暂无用户提交!") + elsif params[:export].present? && params[:export] + normal_status(0,"正在下载中") else respond_to do |format| format.xlsx{ + set_export_cookies student_work_to_xlsx(@work_excel,@homework) exercise_export_name = "#{current_user.real_name}_#{@course.name}_#{@homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" - render xlsx: "#{exercise_export_name.strip.first(30)}",template: "homework_commons/works_list.xlsx.axlsx",locals: + render xlsx: "#{exercise_export_name.strip}",template: "homework_commons/works_list.xlsx.axlsx",locals: {table_columns: @work_head_cells,task_users: @work_cells_column} } end @@ -229,12 +232,17 @@ class HomeworkCommonsController < ApplicationController end if status == 0 - respond_to do |format| - format.zip{ - zipfile = zip_homework_common @homework, zip_works - file = decode64(zipfile[0][:base64file]) - send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' - } + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + respond_to do |format| + format.zip{ + set_export_cookies + zipfile = zip_homework_common @homework, zip_works + file = decode64(zipfile[0][:base64file]) + send_file "#{OUTPUT_FOLDER}/#{file}", filename: filename_for_content_disposition(file), type: 'application/zip' + } + end end else normal_status(status, status == -2 ? "500M" : "无附件可下载") diff --git a/app/controllers/memos_controller.rb b/app/controllers/memos_controller.rb index 723f2e9a4..869d787db 100644 --- a/app/controllers/memos_controller.rb +++ b/app/controllers/memos_controller.rb @@ -66,9 +66,7 @@ class MemosController < ApplicationController # GET /memos/new def new - @csrf_token = session[:_csrf_toke] ||= SecureRandom.base64(32) @tag_list = TagRepertoire.field_for_list.order("name asc") - end # GET /memos/1/edit diff --git a/app/controllers/myshixuns_controller.rb b/app/controllers/myshixuns_controller.rb index fa47fd7f6..1d6b15969 100644 --- a/app/controllers/myshixuns_controller.rb +++ b/app/controllers/myshixuns_controller.rb @@ -24,7 +24,7 @@ class MyshixunsController < ApplicationController ActiveRecord::Base.transaction do begin @shixun = Shixun.select(:id, :identifier).find(@myshixun.shixun_id) - @myshixun.destroy + @myshixun.destroy! StudentWork.where(:myshixun_id => @myshixun.id).update_all(:myshixun_id => 0, :work_status => 0) diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb index 4348b3bfc..7d978d722 100644 --- a/app/controllers/polls_controller.rb +++ b/app/controllers/polls_controller.rb @@ -945,12 +945,15 @@ class PollsController < ApplicationController tip_exception(403,"无权限操作") elsif (@poll.polls_status == 1) || (@poll_export_questions.size == 0) || (@poll_commit_ids.size == 0) normal_status(-1,"暂无用户提交") + elsif params[:export].present? && params[:export] + normal_status(0,"正在下载中") else respond_to do |format| format.xlsx{ + set_export_cookies polls_export_name_ = "#{current_user.real_name}_#{@course.name}_#{@poll.polls_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" polls_user_commit = poll_commit_result(@poll,@poll_export_questions,@poll_users,@poll_commit_ids) - render xlsx: "#{polls_export_name_.strip.first(30)}",template: "polls/commit_result.xlsx.axlsx",locals: {polls_user_commit:polls_user_commit} + render xlsx: "#{polls_export_name_.strip}",template: "polls/commit_result.xlsx.axlsx",locals: {polls_user_commit:polls_user_commit} } end end diff --git a/app/controllers/projects/base_controller.rb b/app/controllers/projects/base_controller.rb new file mode 100644 index 000000000..d874b4759 --- /dev/null +++ b/app/controllers/projects/base_controller.rb @@ -0,0 +1,5 @@ +class Projects::BaseController < ApplicationController + include PaginateHelper + + before_action :require_login, :check_auth +end diff --git a/app/controllers/projects/project_applies_controller.rb b/app/controllers/projects/project_applies_controller.rb new file mode 100644 index 000000000..37d9d615e --- /dev/null +++ b/app/controllers/projects/project_applies_controller.rb @@ -0,0 +1,14 @@ +class Projects::ProjectAppliesController < Projects::BaseController + def create + project = Projects::ApplyJoinService.call(current_user, create_params) + render_ok(project_id: project.id) + rescue Projects::ApplyJoinService::Error => ex + render_error(ex.message) + end + + private + + def create_params + params.permit(:code, :role) + end +end \ No newline at end of file diff --git a/app/controllers/shixuns_controller.rb b/app/controllers/shixuns_controller.rb index 1c272e02d..26effd12e 100644 --- a/app/controllers/shixuns_controller.rb +++ b/app/controllers/shixuns_controller.rb @@ -714,9 +714,10 @@ class ShixunsController < ApplicationController end end rescue Exception => e + logger.info("shixun_exec error: #{e.message}") if e.message != "ActiveRecord::RecordInvalid" logger.error("##########project_fork error #{e.message}") - @current_task.destroy! + @myshixun.destroy! end raise "实训云平台繁忙(繁忙等级:81)" end diff --git a/app/controllers/student_works_controller.rb b/app/controllers/student_works_controller.rb index f9f4717a6..a5d46e46a 100644 --- a/app/controllers/student_works_controller.rb +++ b/app/controllers/student_works_controller.rb @@ -457,8 +457,8 @@ class StudentWorksController < ApplicationController @myself_eff = @echart_data[:efficiency_list].find { |item| item.last == @user.id } @myself_consume = @echart_data[:consume_list].find { |item| item.last == @user.id } - filename_ = "实训报告_#{@shixun&.name}_#{@use&.real_name}" - filename = Base64.urlsafe_encode64(filename_.strip.first(30)) + filename_ = "#{@use&.student_id}_#{@use&.real_name}_#{@shixun&.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" + filename = Base64.urlsafe_encode64(filename_.strip) stylesheets = %w(shixun_work/shixun_work.css shared/codemirror.css) render pdf: 'shixun_work/shixun_work', filename: filename, stylesheets: stylesheets end diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb index afc03ee13..fd138a182 100644 --- a/app/controllers/users/base_controller.rb +++ b/app/controllers/users/base_controller.rb @@ -26,9 +26,22 @@ class Users::BaseController < ApplicationController render_forbidden end + def page_value + params[:page].to_i <= 0 ? 1 : params[:page].to_i + end + + def per_page_value + params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : 20 + end + alias_method :limit_value, :per_page_value + + def offset_value + (page_value - 1) * limit_value + end + def paginate(objs, **opts) - 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 + page = page_value + per_page = per_page_value return Kaminari.paginate_array(objs).page(page).per(per_page) unless observed_logged_user? && opts[:special] diff --git a/app/controllers/users/private_message_details_controller.rb b/app/controllers/users/private_message_details_controller.rb new file mode 100644 index 000000000..486d23d7f --- /dev/null +++ b/app/controllers/users/private_message_details_controller.rb @@ -0,0 +1,23 @@ +class Users::PrivateMessageDetailsController < Users::BaseController + before_action :private_user_resources! + + after_action :update_message_status, only: [:show] + + def show + messages = observed_user.private_messages.without_deleted.where(target: target_user) + + @count = messages.count + @messages = messages.order(send_time: :asc).includes(sender: :user_extension) + end + + private + + def target_user + @_target_user ||= User.find(params[:target_id]) + end + + # 置为已读 + def update_message_status + observed_user.private_messages.only_unread.where(target: target_user).update_all(status: 1) + end +end \ No newline at end of file diff --git a/app/controllers/users/private_messages_controller.rb b/app/controllers/users/private_messages_controller.rb new file mode 100644 index 000000000..b80b6152b --- /dev/null +++ b/app/controllers/users/private_messages_controller.rb @@ -0,0 +1,39 @@ +class Users::PrivateMessagesController < Users::BaseController + before_action :private_user_resources! + after_action :update_onclick_time!, only: [:index] + + def index + @count = observed_user.private_messages.without_deleted.group(:target_id).count.count + + subquery = observed_user.private_messages.without_deleted.order(send_time: :desc).to_sql + query = "SELECT subquery.*, COUNT(*) message_count FROM (#{subquery}) subquery "\ + "GROUP BY subquery.target_id ORDER BY subquery.send_time desc LIMIT #{limit_value} OFFSET #{offset_value}" + @messages = PrivateMessage.select('*').from("(#{query}) AS query").includes(target: :user_extension) + end + + def create + receiver = User.find_by(id: params[:target_id]) + return render_error('用户未找到') if receiver.blank? + + @message = PrivateMessages::CreateService.call(observed_user, receiver, create_params) + rescue PrivateMessages::CreateService::Error => ex + render_error(ex.message) + end + + def destroy + message = observed_user.private_messages.without_deleted.find(params[:id]) + message.destroy! + + render_ok + end + + private + + def update_onclick_time! + current_user.onclick_time.touch(:onclick_time) + end + + def create_params + params.permit(:content) + end +end \ No newline at end of file diff --git a/app/controllers/users/recent_contacts_controller.rb b/app/controllers/users/recent_contacts_controller.rb new file mode 100644 index 000000000..bc4b8ea8f --- /dev/null +++ b/app/controllers/users/recent_contacts_controller.rb @@ -0,0 +1,8 @@ +class Users::RecentContactsController < Users::BaseController + before_action :private_user_resources! + + def index + contacts = observed_user.recent_contacts.distinct + @contacts = contacts.order('private_messages.created_at DESC').limit(10).includes(:user_extension) + end +end \ No newline at end of file diff --git a/app/controllers/users/unread_message_infos_controller.rb b/app/controllers/users/unread_message_infos_controller.rb new file mode 100644 index 000000000..7abd36304 --- /dev/null +++ b/app/controllers/users/unread_message_infos_controller.rb @@ -0,0 +1,12 @@ +class Users::UnreadMessageInfosController < Users::BaseController + before_action :private_user_resources! + + def show + click_time = observed_user.click_time + + unread_tiding_count = observed_user.tidings.where('created_at > ?', click_time).count + unread_message_count = observed_user.private_messages.only_unread.group(:target_id).count.count + + render_ok(unread_tiding_count: unread_tiding_count, unread_message_count: unread_message_count) + end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 23f6870c8..a1f6a5495 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -73,8 +73,7 @@ class UsersController < ApplicationController @user_url = "/users/#{@user.login}" @career = Career.where(status: true).order("created_at asc").pluck(:id, :name) - ec_user = EcSchoolUser.where(:user_id => current_user.id).first - @auth = ec_user ? "#{@old_domain}/ecs/department?school_id=#{ec_user.school_id}" : nil + @auth = User.current.ec_school.present? ? "#{@old_domain}/ecs/department?school_id=#{User.current.ec_school}" : nil end # 用户回复功能 diff --git a/app/controllers/users_for_private_messages_controller.rb b/app/controllers/users_for_private_messages_controller.rb new file mode 100644 index 000000000..bbd5682a1 --- /dev/null +++ b/app/controllers/users_for_private_messages_controller.rb @@ -0,0 +1,17 @@ +class UsersForPrivateMessagesController < ApplicationController + before_action :require_login, :check_auth + + def index + users = User.active.where.not(id: current_user.id) + + keyword = params[:keyword].to_s.strip + if keyword.blank? + @users = [] + return + end + + users = users.where('LOWER(concat(lastname, firstname, nickname)) LIKE ?', "%#{keyword}%") + + @users = users.limit(10).includes(:user_extension) + end +end \ No newline at end of file diff --git a/app/controllers/zips_controller.rb b/app/controllers/zips_controller.rb index f4822b96b..3ed1eb8b3 100644 --- a/app/controllers/zips_controller.rb +++ b/app/controllers/zips_controller.rb @@ -8,7 +8,13 @@ class ZipsController < ApplicationController def shixun_report service = BatchExportShixunReportService.new(@homework, @all_student_works) filename_ = filename_for_content_disposition(service.filename) - send_file service.zip, filename: filename_, type: 'application/zip' + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + set_export_cookies + send_file service.zip, filename: filename_, type: 'application/zip' + end + rescue BatchExportShixunReportService::Error => ex normal_status(-1, ex.message) end @@ -18,7 +24,12 @@ class ZipsController < ApplicationController exercises = ExportExercisesService.new(@exercise,@ex_users,@request_url) file_name_ = filename_for_content_disposition(exercises.filename) - send_file exercises.ex_zip, filename: file_name_, type: 'application/zip' + if params[:export].present? && params[:export] + normal_status(0,"正在下载中") + else + set_export_cookies + send_file exercises.ex_zip, filename: file_name_, type: 'application/zip' + end rescue Exception => e normal_status(-1, e.message) end diff --git a/app/decorators/private_message_decorator.rb b/app/decorators/private_message_decorator.rb new file mode 100644 index 000000000..6db17acf3 --- /dev/null +++ b/app/decorators/private_message_decorator.rb @@ -0,0 +1,9 @@ +module PrivateMessageDecorator + extend ApplicationDecorator + + display_time_method :send_time + + def unread? + status.zero? + end +end \ No newline at end of file diff --git a/app/decorators/tiding_decorator.rb b/app/decorators/tiding_decorator.rb index 8d383dadf..c9ad806ee 100644 --- a/app/decorators/tiding_decorator.rb +++ b/app/decorators/tiding_decorator.rb @@ -98,7 +98,7 @@ module TidingDecorator end def apply_add_schools_content - name = container.name + name = ApplyAddSchool.find_by(id: container_id)&.name if tiding_type == 'Apply' I18n.t(locale_format(tiding_type)) % name elsif status == 2 @@ -201,7 +201,7 @@ module TidingDecorator when 'Issue' then I18n.t(locale_format(parent_container_type)) % parent_container.subject when 'Journal' then - message = object.notes.present? ? ':' + message_content_helper(parent_container.notes) : '' + message = parent_container&.notes.present? ? ':' + message_content_helper(parent_container.notes) : '' I18n.t(locale_format(parent_container_type)) % message end end @@ -331,13 +331,17 @@ module TidingDecorator end def challenge_work_score_content + I18n.t(locale_format) % container&.comment + end + + def student_works_scores_appeal_content work = StudentWork.find_by(id: parent_container_id) - return if work.blank? + name = work&.homework_common&.name if parent_container_type == 'StudentWork' - I18n.t(locale_format(parent_container_type, tiding_type)) % work.homework_common.try(:name) - elsif parent_container_type == 'UserAppealResult' || parent_container_type == 'AppealResult' - I18n.t(locale_format(parent_container_type, status)) % work.homework_common.try(:name) + I18n.t(locale_format(parent_container_type, tiding_type)) % name + else + I18n.t(locale_format(parent_container_type, status)) % name end end @@ -349,7 +353,7 @@ module TidingDecorator if tiding_type == 'System' I18n.t(locale_format(tiding_type, status), reason: extra) % container.try(:title) else - I18n.t(locale_format) % container.try(:title) + I18n.t(locale_format(tiding_type)) % container.try(:title) end end diff --git a/app/helpers/export_helper.rb b/app/helpers/export_helper.rb index 742deb85b..5d36c465f 100644 --- a/app/helpers/export_helper.rb +++ b/app/helpers/export_helper.rb @@ -418,7 +418,7 @@ module ExportHelper end end - out_file_name = "#{Time.now.to_i}_#{homework_common.name}.zip" + out_file_name = "作品附件_#{homework_common&.course&.name}_#{homework_common.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.zip" out_file_name.gsub!(" ", "-") out_file_name.gsub!("/", "_") out_file = find_or_pack(homework_common, homework_common.user_id, digests.sort){ @@ -496,8 +496,8 @@ module ExportHelper def make_zip_name(work, file_name="") Rails.logger.info("######################file_name: #{file_name}") - name = file_name === "" ? "" : (file_name[0, file_name.rindex('.')]+"_") - "#{name}#{work.user.real_name}_#{((work.user.student_id.nil?) ? "" : work.user.student_id)}" + # name = file_name === "" ? "" : (file_name[0, file_name.rindex('.')]+"_") + "#{work&.user&.student_id}_#{work&.user&.real_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" end def zipping(zip_name_refer, files_paths, output_path, is_attachment=false, not_exist_file=[]) diff --git a/app/helpers/forums_helper.rb b/app/helpers/forums_helper.rb new file mode 100644 index 000000000..2e531fd46 --- /dev/null +++ b/app/helpers/forums_helper.rb @@ -0,0 +1,2 @@ +module ForumsHelper +end diff --git a/app/helpers/games_helper.rb b/app/helpers/games_helper.rb index aff05904f..5a9871673 100644 --- a/app/helpers/games_helper.rb +++ b/app/helpers/games_helper.rb @@ -6,7 +6,7 @@ module GamesHelper end # 获取目录下所有文件,返回一个文件名的数组 type是查看文件的类型image表示图片 - # type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"]] + # type [[1, "图片"], [2, "apk/exe"], [3, "txt"], [4, "html"], [5, "mp3"], [6, "mp4"]] def get_dir_filename(path, type, game_id) answer_picture = [] return answer_picture unless File.directory?(path) @@ -39,6 +39,12 @@ module GamesHelper end f.close @type = 'txt' + elsif extension == 'mp3' && type == 5 + answer_picture << file + @type = 'mp3' + elsif extension == 'mp4' && type == 6 + answer_picture << file + @type = 'mp4' end end @@ -51,4 +57,21 @@ module GamesHelper "编译失败,请在测试结果中查看具体的错误信息" : test_set.try(:actual_output) end end + + def shixun_show_type type + case type.to_i + when 1 + "image" + when 2 + "apk/exe" + when 3 + "txt" + when 4 + "html" + when 5 + "mp3" + when 6 + "mp4" + end + end end diff --git a/app/helpers/memos_helper.rb b/app/helpers/memos_helper.rb index 7df887a4b..434d9b66a 100644 --- a/app/helpers/memos_helper.rb +++ b/app/helpers/memos_helper.rb @@ -1,2 +1,6 @@ module MemosHelper + + def forum_list + [{id: 5, name: "技术分享"}, {id: 3, name: "操作指南"}] + end end diff --git a/app/jobs/apply_join_project_notify_job.rb b/app/jobs/apply_join_project_notify_job.rb new file mode 100644 index 000000000..fe46bf0e0 --- /dev/null +++ b/app/jobs/apply_join_project_notify_job.rb @@ -0,0 +1,31 @@ +# 申请成为 管理员、开发者 加入项目 消息通知 +class ApplyJoinProjectNotifyJob < ApplicationJob + queue_as :notify + + def perform(user_id, project_id, role) + user = User.find_by(id: user_id) + project = Project.find_by(id: project_id) + return if user.blank? || project.blank? + + attrs = %i[user_id trigger_user_id container_id container_type status + belong_container_id belong_container_type tiding_type extra created_at updated_at] + + same_attrs = { + trigger_user_id: user.id, status: 0, tiding_type: 'Apply', extra: role, + container_id: project.id, container_type: 'JoinProject', + belong_container_id: project.id, belong_container_type: 'Project' + } + + # 报告人员加入时消息为系统通知消息 + if role == 5 + same_attrs[:container_type] = 'ReporterJoinProject' + same_attrs[:tiding_type] = 'System' + end + + Tiding.bulk_insert(*attrs) do |worker| + project.manager_members.each do |manager| + worker.add(same_attrs.merge(user_id: manager.user_id)) + end + end + end +end diff --git a/app/models/applied_project.rb b/app/models/applied_project.rb new file mode 100644 index 000000000..901443e81 --- /dev/null +++ b/app/models/applied_project.rb @@ -0,0 +1,9 @@ +class AppliedProject < ApplicationRecord + belongs_to :user + belongs_to :project + + has_many :applied_messages, as: :applied, dependent: :destroy + has_many :forge_activities, as: :forge_act, dependent: :destroy + + scope :pending, -> { where(status: 0) } +end diff --git a/app/models/challenge.rb b/app/models/challenge.rb index 0bea54eb4..8e4d2ae42 100644 --- a/app/models/challenge.rb +++ b/app/models/challenge.rb @@ -1,5 +1,6 @@ class Challenge < ApplicationRecord # difficulty: 关卡难度: 1.简单 2.中等 3.困难 + # show_type: 效果展示:-1.无效果 1.图片 2.apk/exe 3.txt 4.html 5.mp3 6.mp4 default_scope { order("challenges.position asc") } belongs_to :shixun, :touch => true, counter_cache: true diff --git a/app/models/forge_activity.rb b/app/models/forge_activity.rb new file mode 100644 index 000000000..77103d0ff --- /dev/null +++ b/app/models/forge_activity.rb @@ -0,0 +1,5 @@ +class ForgeActivity < ApplicationRecord + belongs_to :user + belongs_to :project + belongs_to :forge_act, polymorphic: true +end \ No newline at end of file diff --git a/app/models/forum.rb b/app/models/forum.rb new file mode 100644 index 000000000..88aafa676 --- /dev/null +++ b/app/models/forum.rb @@ -0,0 +1,2 @@ +class Forum < ApplicationRecord +end diff --git a/app/models/journal.rb b/app/models/journal.rb new file mode 100644 index 000000000..25c1e2498 --- /dev/null +++ b/app/models/journal.rb @@ -0,0 +1,4 @@ +class Journal < ApplicationRecord + belongs_to :user + belongs_to :issue, foreign_key: :journalized_id +end \ No newline at end of file diff --git a/app/models/member.rb b/app/models/member.rb index d1feb8a37..70b7fe305 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -1,6 +1,8 @@ class Member < ApplicationRecord - has_many :member_roles, dependent: :destroy + belongs_to :user belongs_to :course, optional: true belongs_to :project, optional: true - belongs_to :user + + has_many :member_roles, dependent: :destroy + has_many :roles, through: :member_roles end diff --git a/app/models/member_role.rb b/app/models/member_role.rb index 900efc732..2461c52f1 100644 --- a/app/models/member_role.rb +++ b/app/models/member_role.rb @@ -1,3 +1,4 @@ class MemberRole < ApplicationRecord + belongs_to :role belongs_to :member end diff --git a/app/models/memo.rb b/app/models/memo.rb index 610a7684d..4dc153c81 100644 --- a/app/models/memo.rb +++ b/app/models/memo.rb @@ -1,7 +1,9 @@ class Memo < ApplicationRecord include Searchable::Memo - has_many :memo_tag_repertoires, :dependent => :destroy + belongs_to :forum, touch: true + + has_many :memo_tag_repertoires, dependent: :destroy has_many :tag_repertoires, :through => :memo_tag_repertoires has_many :praise_tread, as: :praise_tread_object, dependent: :destroy diff --git a/app/models/private_message.rb b/app/models/private_message.rb index 1db4c9f66..640e48db7 100644 --- a/app/models/private_message.rb +++ b/app/models/private_message.rb @@ -1,3 +1,9 @@ class PrivateMessage < ApplicationRecord belongs_to :user + belongs_to :target, class_name: "User" + belongs_to :sender, class_name: "User" + belongs_to :receiver, class_name: "User" + + scope :without_deleted, -> { where.not(status: 2) } + scope :only_unread, -> { where(status: 0) } end diff --git a/app/models/project.rb b/app/models/project.rb index ddc6f6e5f..c3c626cb0 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,9 +1,12 @@ class Project < ApplicationRecord belongs_to :owner, class_name: 'User', foreign_key: :user_id + has_many :members + has_many :manager_members, -> { joins(:roles).where(roles: { name: 'Manager' }) }, class_name: 'Member' has_one :project_score, dependent: :destroy has_many :issues + has_many :user_grades, dependent: :destroy # 创建者 def creator diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 000000000..e60606ffa --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,3 @@ +class Role < ApplicationRecord + has_many :member_roles, dependent: :destroy +end \ No newline at end of file diff --git a/app/models/searchable/dependents/user.rb b/app/models/searchable/dependents/user.rb index f6dcaa430..bb55d0530 100644 --- a/app/models/searchable/dependents/user.rb +++ b/app/models/searchable/dependents/user.rb @@ -8,7 +8,7 @@ module Searchable::Dependents::User private def check_searchable_dependents - if firstname_previously_changed? || lastname_previously_changed? || user_extension.school_id_previously_changed? + if firstname_previously_changed? || lastname_previously_changed? || user_extension&.school_id_previously_changed? # reindex shixun created_shixuns.each(&:reindex) diff --git a/app/models/tiding.rb b/app/models/tiding.rb index 66b1f85be..90abdf809 100644 --- a/app/models/tiding.rb +++ b/app/models/tiding.rb @@ -6,4 +6,21 @@ class Tiding < ApplicationRecord belongs_to :belong_container, polymorphic: true, optional: true has_many :attachments, as: :container + + def identifier + value = nil + if Object.const_defined?(container_type) + value = container.try(:identifier) + end + + if value.blank? && parent_container_type && Object.const_defined?(parent_container_type) + value = parent_container_type.try(:identifier) + end + + if value.blank? && belong_container_type && Object.const_defined?(belong_container_type) + value = belong_container.try(:identifier) + end + + value + end end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index f2d9c7fb1..ed9d70c00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -54,7 +54,8 @@ class User < ApplicationRecord has_one :onclick_time, :dependent => :destroy # 新版私信 - has_many :private_messages, :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 @@ -128,6 +129,9 @@ class User < ApplicationRecord has_many :bidding_users, dependent: :destroy has_many :bidden_project_packages, through: :bidding_users, source: :project_package + # 项目 + has_many :applied_projects, dependent: :destroy + # Groups and active users scope :active, lambda { where(status: STATUS_ACTIVE) } @@ -497,6 +501,13 @@ class User < ApplicationRecord ) 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 diff --git a/app/models/user_grade.rb b/app/models/user_grade.rb new file mode 100644 index 000000000..dffbb4743 --- /dev/null +++ b/app/models/user_grade.rb @@ -0,0 +1,4 @@ +class UserGrade < ApplicationRecord + belongs_to :project + belongs_to :user +end diff --git a/app/services/batch_export_shixun_report_service.rb b/app/services/batch_export_shixun_report_service.rb index d71235790..253eb4480 100644 --- a/app/services/batch_export_shixun_report_service.rb +++ b/app/services/batch_export_shixun_report_service.rb @@ -14,7 +14,7 @@ class BatchExportShixunReportService end def filename - @_filename ||= "#{homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" + @_filename ||= "实训报告_#{homework&.course&.name}_#{homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" end def zip diff --git a/app/services/concerns/elasticsearch_able.rb b/app/services/concerns/elasticsearch_able.rb index c1640470c..e93f9c537 100644 --- a/app/services/concerns/elasticsearch_able.rb +++ b/app/services/concerns/elasticsearch_able.rb @@ -22,6 +22,7 @@ module ElasticsearchAble fragment_size: EduSetting.get('es_highlight_fragment_size') || 30, tag: '', fields: { + name: { type: 'plain' }, challenge_names: { type: 'plain' }, challenge_tag_names: { type: 'plain' }, description: { type: 'plain' }, diff --git a/app/services/exercise_user_pdf_service.rb b/app/services/exercise_user_pdf_service.rb index 73711192f..6891e53ea 100644 --- a/app/services/exercise_user_pdf_service.rb +++ b/app/services/exercise_user_pdf_service.rb @@ -15,8 +15,8 @@ class ExerciseUserPdfService end def filename - user_course = @course.course_members.find_by(user_id:@ex_user_user.id)&.course_group_name - exercise_user_name = "#{@ex_user_user.real_name}_#{user_course.present? ? user_course : "未分班"}_#{exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M')}" + # user_course = @course.course_members.find_by(user_id:@ex_user_user.id)&.course_group_name + exercise_user_name = "#{@ex_user_user&.student_id}_#{@ex_user_user.real_name}_#{exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M')}" "#{exercise_user_name.strip}.pdf" end diff --git a/app/services/export_exercises_service.rb b/app/services/export_exercises_service.rb index ca2d347a6..1f1e15326 100644 --- a/app/services/export_exercises_service.rb +++ b/app/services/export_exercises_service.rb @@ -10,7 +10,7 @@ class ExportExercisesService end def filename - exercise_export_name = "#{exercise.user.real_name}_#{exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" + exercise_export_name = "学生答题_#{exercise&.course&.name}_#{exercise.exercise_name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}" "#{exercise_export_name.strip}.zip" end diff --git a/app/services/export_shixun_report_service.rb b/app/services/export_shixun_report_service.rb index f9da3d6f2..57b955762 100644 --- a/app/services/export_shixun_report_service.rb +++ b/app/services/export_shixun_report_service.rb @@ -10,7 +10,7 @@ class ExportShixunReportService end def filename - @_filename ||= "#{homework.name}-#{work.user&.student_id}-#{work.user.real_name}.pdf".gsub(' ', '-').gsub('/', '_') + @_filename ||= "#{work.user&.student_id}_#{work.user.real_name}_#{homework.name}_#{Time.now.strftime('%Y%m%d_%H%M%S')}.pdf".gsub(' ', '-').gsub('/', '_') end def prepare_binding diff --git a/app/services/private_messages/create_service.rb b/app/services/private_messages/create_service.rb new file mode 100644 index 000000000..560f1a540 --- /dev/null +++ b/app/services/private_messages/create_service.rb @@ -0,0 +1,35 @@ +class PrivateMessages::CreateService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :sender, :receiver, :params + + def initialize(sender, receiver, **params) + @sender = sender + @receiver = receiver + @params = params + end + + def call + validate! + + same_attr = { sender: sender, receiver: receiver, content: content, send_time: Time.now } + + message = nil + ActiveRecord::Base.transaction do + message = sender.private_messages.create!(same_attr.merge(target: receiver, status: 1)) + receiver.private_messages.create!(same_attr.merge(target: sender, status: 0)) + end + message + end + + private + + def content + @_content ||= params[:content].to_s.strip + end + + def validate! + raise Error, '内容不能为空' if content.blank? + raise Error, '内容太长' if content.size > 255 + end +end \ No newline at end of file diff --git a/app/services/project_packages/save_service.rb b/app/services/project_packages/save_service.rb index bcfc19a10..a876f56b3 100644 --- a/app/services/project_packages/save_service.rb +++ b/app/services/project_packages/save_service.rb @@ -15,7 +15,7 @@ class ProjectPackages::SaveService < ApplicationService is_create = package.new_record? raise Error, '类型不存在' unless ProjectPackageCategory.where(id: params[:category_id]).exists? - params[:project_package_category_id] = params[:category_id].to_i + params[:project_package_category_id] = params.delete(:category_id).to_i raise Error, '竞标截止时间不能小于当前时间' if params[:deadline_at].present? && params[:deadline_at].to_time < Time.now @@ -25,7 +25,9 @@ class ProjectPackages::SaveService < ApplicationService end ActiveRecord::Base.transaction do - package.assign_attributes(params) + columns = %i[project_package_category_id title content deadline_at + min_price max_price contact_name contact_phone] + package.assign_attributes(params.slice(*columns)) package.save! # 处理附件 diff --git a/app/services/projects/apply_join_service.rb b/app/services/projects/apply_join_service.rb new file mode 100644 index 000000000..a177de930 --- /dev/null +++ b/app/services/projects/apply_join_service.rb @@ -0,0 +1,82 @@ +class Projects::ApplyJoinService < ApplicationService + Error = Class.new(StandardError) + + attr_reader :user, :params + + def initialize(user, params) + @user = user + @params = params + end + + def call + validate! + + # 项目报告人员直接加入项目 + if params[:role] == 'reporter' + Projects::JoinService.call(project, user, role: 'reporter') + return project + end + + ActiveRecord::Base.transaction do + apply = user.applied_projects.create!(project: project, role: role_value) + + apply.forge_activities.find_or_create_by!(user: user, project: project) + + notify_project_manager! + end + + # notify_project_owner + ApplyJoinProjectNotifyJob.perform_later(user.id, project.id, role_value) + + project + end + + private + + def project + @_project ||= Project.find_by(invite_code: params[:code].to_s.strip) + end + + def role_value + @_role ||= + case params[:role] + when 'manager' then 3 + when 'developer' then 4 + when 'reporter' then 5 + else raise Error, '角色无效' + end + end + + def notify_project_manager! + columns = %i[user_id applied_id applied_type status viewed applied_user_id role project_id created_at updated_at] + AppliedMessage.bulk_insert(*columns) do |worker| + base_attr = { status: false, viewed: false, applied_user_id: user.id, role: role_value, project_id: project.id } + + project.manager_members.each do |manager| + worker.add(base_attr.merge(user_id: manager.user_id)) + end + end + end + + def notify_project_owner + owner = project.user + return if owner.phone.blank? + + Educoder::Sms.send(mobile: owner.phone, send_type:'applied_project_info', + user_name: owner.show_name, name: project.name) + rescue Exception => ex + Rails.logger.error("发送短信失败 => #{ex.message}") + end + + def validate! + # params check + raise Error, '邀请码不能为空' if params[:code].blank? + raise Error, '角色不能为空' if params[:role].blank? + raise Error, '角色无效' unless %w(manager developer reporter).include?(params[:role]) + + # logical check + raise Error, '邀请码无效' if project.blank? + raise Error, '您已在该项目中' if project.member?(user) + raise Error, '您已经提交过申请' if user.applied_projects.pending.exists?(project: project) + end +end \ No newline at end of file diff --git a/app/services/projects/join_service.rb b/app/services/projects/join_service.rb new file mode 100644 index 000000000..b434e48cd --- /dev/null +++ b/app/services/projects/join_service.rb @@ -0,0 +1,35 @@ +class Projects::JoinService < ApplicationService + attr_reader :project, :user, :opts + + def initialize(project, user, **opts) + @project = project + @user = user + @opts = opts + end + + def call + ActiveRecord::Base.transaction do + member = project.members.create!(user: user) + + member.member_roles.create!(role_id: role_value) + + project.user_grades.find_or_create_by!(user: user) + end + + ApplyJoinProjectNotifyJob.perform_later(user, project, role_value) + + project + end + + private + + def role_value + @_role ||= + case opts[:role] + when 'manager' then 3 + when 'developer' then 4 + when 'reporter' then 5 + else raise ArgumentError + end + end +end \ No newline at end of file diff --git a/app/views/courses/search_users.json.jbuilder b/app/views/courses/search_users.json.jbuilder index ac826fdf2..61362de66 100644 --- a/app/views/courses/search_users.json.jbuilder +++ b/app/views/courses/search_users.json.jbuilder @@ -1,6 +1,7 @@ json.users do json.array! @users do |user| json.id user.id + json.login user.login json.name user.real_name json.student_id user&.student_id json.school_name user&.school_name diff --git a/app/views/games/picture_display.json.jbuilder b/app/views/games/picture_display.json.jbuilder index 541c478a9..b43efa57e 100644 --- a/app/views/games/picture_display.json.jbuilder +++ b/app/views/games/picture_display.json.jbuilder @@ -24,5 +24,30 @@ elsif @type == "txt" json.contents @contents.html_safe elsif @type =="qrcode" json.qrcode_str @qrcode_str +elsif @type == "mp3" || @type == "mp4" + if @type == "mp4" + json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378171/123.mp4"}] + json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378172/456.mp4"}] + json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378173/789.mp4"}] + else + json.orignal_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378174/58099.mp3"}] + json.user_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] + json.answer_file [{"file_url": "http://120.27.231.56:48080/attachments/download/378175/654058514.mp3"}] + end + # json.orignal_file do + # json.array! @orignal_picture do |file| + # json.file_url attachment_show_users_path(:file_name => file, :path => @original_path) + # end + # end + # json.user_file do + # json.array! @user_picture do |file| + # json.file_url attachment_show_users_path(:file_name => file, :path => @user_path, :time => Time.now.to_i) + # end + # end + # json.answer_file do + # json.array! @answer_picture do |file| + # json.file_url attachment_show_users_path(:file_name => file, :path => @answer_path) + # end + # end end \ No newline at end of file diff --git a/app/views/memos/new.json.jbuilder b/app/views/memos/new.json.jbuilder index 14313b2ac..47c023ea0 100644 --- a/app/views/memos/new.json.jbuilder +++ b/app/views/memos/new.json.jbuilder @@ -1,3 +1,3 @@ json.tag_list @tag_list -json.csrf_token @csrf_token +json.forums @csrf_token diff --git a/app/views/tidings/_tiding.json.jbuilder b/app/views/tidings/_tiding.json.jbuilder index d26d37b7b..34b06320d 100644 --- a/app/views/tidings/_tiding.json.jbuilder +++ b/app/views/tidings/_tiding.json.jbuilder @@ -1,6 +1,6 @@ json.extract! tiding, :id, :status, :viewed, :user_id, :tiding_type, :container_id, :container_type, :parent_container_id, :parent_container_type json.content tiding.content -json.identifier tiding.try(:container).try(:identifier) rescue nil +json.identifier tiding.identifier json.time tiding.how_long_time json.new_tiding tiding.unread?(@onclick_time) diff --git a/app/views/users/get_user_info.json.jbuilder b/app/views/users/get_user_info.json.jbuilder index d9eb736ad..d12b950f9 100644 --- a/app/views/users/get_user_info.json.jbuilder +++ b/app/views/users/get_user_info.json.jbuilder @@ -7,6 +7,7 @@ json.is_teacher @user.user_extension&.teacher? json.user_identity @user.identity json.tidding_count 0 json.user_phone_binded @user.phone.present? +json.phone @user.phone json.profile_completed @user.profile_completed? if @course json.course_identity @course_identity diff --git a/app/views/users/private_message_details/show.json.jbuilder b/app/views/users/private_message_details/show.json.jbuilder new file mode 100644 index 000000000..065767fb4 --- /dev/null +++ b/app/views/users/private_message_details/show.json.jbuilder @@ -0,0 +1,11 @@ +json.count @count +json.messages do + json.array! @messages.each do |message| + json.extract! message, :id, :user_id, :receiver_id, :sender_id, :content + + json.send_time message.display_send_time + json.sender do + json.partial! 'users/user_simple', user: message.sender + end + end +end \ No newline at end of file diff --git a/app/views/users/private_messages/create.json.jbuilder b/app/views/users/private_messages/create.json.jbuilder new file mode 100644 index 000000000..888cfeff6 --- /dev/null +++ b/app/views/users/private_messages/create.json.jbuilder @@ -0,0 +1,10 @@ +json.status 0 +json.message 'success' +json.private_message do + json.extract! @message, :id, :user_id, :receiver_id, :sender_id, :content + + json.send_time @message.display_send_time + json.sender do + json.partial! 'users/user_simple', user: @message.sender + end +end \ No newline at end of file diff --git a/app/views/users/private_messages/index.json.jbuilder b/app/views/users/private_messages/index.json.jbuilder new file mode 100644 index 000000000..c18a7d209 --- /dev/null +++ b/app/views/users/private_messages/index.json.jbuilder @@ -0,0 +1,13 @@ +json.count @count +json.private_messages do + json.array! @messages.each do |message| + json.extract! message, :id, :content, :message_count + + json.unread message.unread? + json.send_time message.display_send_time + + json.target do + json.partial! 'users/user_simple', user: message.target + end + end +end \ No newline at end of file diff --git a/app/views/users/recent_contacts/index.json.jbuilder b/app/views/users/recent_contacts/index.json.jbuilder new file mode 100644 index 000000000..f2f7f025a --- /dev/null +++ b/app/views/users/recent_contacts/index.json.jbuilder @@ -0,0 +1,2 @@ +json.users @contacts, partial: 'users/user_simple', as: :user +json.count @contacts.size \ No newline at end of file diff --git a/app/views/users_for_private_messages/index.json.jbuilder b/app/views/users_for_private_messages/index.json.jbuilder new file mode 100644 index 000000000..be040e368 --- /dev/null +++ b/app/views/users_for_private_messages/index.json.jbuilder @@ -0,0 +1,2 @@ +json.users @users, partial: 'users/user_simple', as: :user +json.count @users.size \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 6024201a4..2f9eed61b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -53,6 +53,11 @@ Rails.application.routes.draw do resource :grade_records, only: [:show] resource :watch, only: [:create, :destroy] resources :project_packages, only: [:index] + # 私信 + resources :private_messages, only: [:index, :create, :destroy] + resources :recent_contacts, only: [:index] + resource :private_message_details, only: [:show] + resource :unread_message_info, only: [:show] end @@ -91,6 +96,7 @@ Rails.application.routes.draw do end end end + resources :users_for_private_messages, only: [:index] resources :myshixuns, param: :identifier, shallow: true do member do @@ -695,6 +701,10 @@ Rails.application.routes.draw do end resources :libraries, only: [:index, :show, :create, :update, :destroy] + + scope module: :projects do + resources :applied_projects, only: [:create] + end end #git 认证回调 diff --git a/db/migrate/20190729080935_modify_login_for_users.rb b/db/migrate/20190729080935_modify_login_for_users.rb new file mode 100644 index 000000000..60e5e0964 --- /dev/null +++ b/db/migrate/20190729080935_modify_login_for_users.rb @@ -0,0 +1,9 @@ +class ModifyLoginForUsers < ActiveRecord::Migration[5.2] + def change + users = User.where("created_on > '2019-07-26 19:00:00'") + users.find_each do |use| + use.update_attributes(login: use.login&.strip, phone: use.phone&.strip) + use.user_extension.update_column(:student_id, use.user_extension&.student_id&.strip) if use.user_extension + end + end +end diff --git a/db/migrate/20190729095722_delete_error_myshixun_from_myshxiuns.rb b/db/migrate/20190729095722_delete_error_myshixun_from_myshxiuns.rb new file mode 100644 index 000000000..ef5b86975 --- /dev/null +++ b/db/migrate/20190729095722_delete_error_myshixun_from_myshxiuns.rb @@ -0,0 +1,11 @@ +class DeleteErrorMyshixunFromMyshxiuns < ActiveRecord::Migration[5.2] + def change + myshixuns = Myshixun.where("created_at > '2019-07-26 00:00:00' and repo_name is null") + myshixuns.find_each do |myshixun| + if myshixun.games.blank? + puts("###########user_login: #{User.find(myshixun.user_id).login}") + myshixun.destroy! + end + end + end +end diff --git a/db/migrate/20190729122213_delete_myshixun_games_for_users.rb b/db/migrate/20190729122213_delete_myshixun_games_for_users.rb new file mode 100644 index 000000000..d52369828 --- /dev/null +++ b/db/migrate/20190729122213_delete_myshixun_games_for_users.rb @@ -0,0 +1,11 @@ +class DeleteMyshixunGamesForUsers < ActiveRecord::Migration[5.2] + def change + myshixuns = Myshixun.where("created_at > '2019-07-26 19:00:00' and repo_name is null") + myshixuns.find_each do |m| + if m.games.count == m.games.select{|g| g.status == 3}.count + puts("#######login: #{User.find(m.user_id).login}") + m.destroy! + end + end + end +end diff --git a/db/migrate/20190730024112_add_index_to_user.rb b/db/migrate/20190730024112_add_index_to_user.rb new file mode 100644 index 000000000..fa198cffa --- /dev/null +++ b/db/migrate/20190730024112_add_index_to_user.rb @@ -0,0 +1,7 @@ +class AddIndexToUser < ActiveRecord::Migration[5.2] + def change + # add_index :users, :login, unique: true + # add_index :users, :mail, unique: true + # add_index :users, :phone, unique: true + end +end diff --git a/public/compatibility.html b/public/compatibility.html index f13c673f5..f28bad2c8 100644 --- a/public/compatibility.html +++ b/public/compatibility.html @@ -5,9 +5,9 @@ EduCoder - - - + + + diff --git a/public/images/educoder/path.png b/public/images/educoder/path.png new file mode 100644 index 000000000..d8b6f1715 Binary files /dev/null and b/public/images/educoder/path.png differ diff --git a/public/images/educoder/project_packages/ai.png b/public/images/educoder/project_packages/ai.png new file mode 100755 index 000000000..825e75165 Binary files /dev/null and b/public/images/educoder/project_packages/ai.png differ diff --git a/public/images/educoder/project_packages/backend.png b/public/images/educoder/project_packages/backend.png new file mode 100755 index 000000000..359bca746 Binary files /dev/null and b/public/images/educoder/project_packages/backend.png differ diff --git a/public/images/educoder/project_packages/cloud_compute_and_big_data.png b/public/images/educoder/project_packages/cloud_compute_and_big_data.png new file mode 100755 index 000000000..42e64da3b Binary files /dev/null and b/public/images/educoder/project_packages/cloud_compute_and_big_data.png differ diff --git a/public/images/educoder/project_packages/database.png b/public/images/educoder/project_packages/database.png new file mode 100755 index 000000000..2b668e774 Binary files /dev/null and b/public/images/educoder/project_packages/database.png differ diff --git a/public/images/educoder/project_packages/devops_and_test.png b/public/images/educoder/project_packages/devops_and_test.png new file mode 100755 index 000000000..77b8e6f3b Binary files /dev/null and b/public/images/educoder/project_packages/devops_and_test.png differ diff --git a/public/images/educoder/project_packages/front.png b/public/images/educoder/project_packages/front.png new file mode 100755 index 000000000..23ba2a755 Binary files /dev/null and b/public/images/educoder/project_packages/front.png differ diff --git a/public/images/educoder/project_packages/mobile.png b/public/images/educoder/project_packages/mobile.png new file mode 100755 index 000000000..cd73520c7 Binary files /dev/null and b/public/images/educoder/project_packages/mobile.png differ diff --git a/public/images/educoder/project_packages/other.png b/public/images/educoder/project_packages/other.png new file mode 100755 index 000000000..a700cd5de Binary files /dev/null and b/public/images/educoder/project_packages/other.png differ diff --git a/public/images/educoder/project_packagesHead.jpg b/public/images/educoder/project_packagesHead.jpg new file mode 100644 index 000000000..181045e03 Binary files /dev/null and b/public/images/educoder/project_packagesHead.jpg differ diff --git a/public/javascripts/download/jquery.fileDownload.js b/public/javascripts/download/jquery.fileDownload.js new file mode 100644 index 000000000..0d0301c23 --- /dev/null +++ b/public/javascripts/download/jquery.fileDownload.js @@ -0,0 +1,490 @@ +/* +* jQuery File Download Plugin v1.4.5 +* +* http://www.johnculviner.com +* +* Copyright (c) 2013 - John Culviner +* +* Licensed under the MIT license: +* http://www.opensource.org/licenses/mit-license.php +* +* !!!!NOTE!!!! +* You must also write a cookie in conjunction with using this plugin in the server's response headers containing the file download: +* Set-Cookie: fileDownload=true; path=/" +* !!!!NOTE!!!! +*/ + +(function($, window){ + // i'll just put them here to get evaluated on script load + var htmlSpecialCharsRegEx = /[<>&\r\n"']/gm; + var htmlSpecialCharsPlaceHolders = { + '<': 'lt;', + '>': 'gt;', + '&': 'amp;', + '\r': "#13;", + '\n': "#10;", + '"': 'quot;', + "'": '#39;' /*single quotes just to be safe, IE8 doesn't support ', so use ' instead */ + }; + +$.extend({ + // + //$.fileDownload('/path/to/url/', options) + // see directly below for possible 'options' + fileDownload: function (fileUrl, options) { + + //provide some reasonable defaults to any unspecified options below + var settings = $.extend({ + + // + //Requires jQuery UI: provide a message to display to the user when the file download is being prepared before the browser's dialog appears + // + preparingMessageHtml: null, + + // + //Requires jQuery UI: provide a message to display to the user when a file download fails + // + failMessageHtml: null, + + // + //the stock android browser straight up doesn't support file downloads initiated by a non GET: http://code.google.com/p/android/issues/detail?id=1780 + //specify a message here to display if a user tries with an android browser + //if jQuery UI is installed this will be a dialog, otherwise it will be an alert + //Set to null to disable the message and attempt to download anyway + // + androidPostUnsupportedMessageHtml: "Unfortunately your Android browser doesn't support this type of file download. Please try again with a different browser.", + + // + //Requires jQuery UI: options to pass into jQuery UI Dialog + // + dialogOptions: { modal: true }, + + // + //a function to call while the dowload is being prepared before the browser's dialog appears + //Args: + // url - the original url attempted + // + prepareCallback: function (url) { }, + + // + //a function to call after a file download successfully completed + //Args: + // url - the original url attempted + // + successCallback: function (url) { }, + + // + //a function to call after a file download request was canceled + //Args: + // url - the original url attempted + // + abortCallback: function (url) { }, + + // + //a function to call after a file download failed + //Args: + // responseHtml - the html that came back in response to the file download. this won't necessarily come back depending on the browser. + // in less than IE9 a cross domain error occurs because 500+ errors cause a cross domain issue due to IE subbing out the + // server's error message with a "helpful" IE built in message + // url - the original url attempted + // error - original error cautch from exception + // + failCallback: function (responseHtml, url, error) { }, + + // + // the HTTP method to use. Defaults to "GET". + // + httpMethod: "GET", + + // + // if specified will perform a "httpMethod" request to the specified 'fileUrl' using the specified data. + // data must be an object (which will be $.param serialized) or already a key=value param string + // + data: null, + + // + //a period in milliseconds to poll to determine if a successful file download has occured or not + // + checkInterval: 100, + + // + //the cookie name to indicate if a file download has occured + // + cookieName: "fileDownload", + + // + //the cookie value for the above name to indicate that a file download has occured + // + cookieValue: "true", + + // + //the cookie path for above name value pair + // + cookiePath: "/", + + // + //if specified it will be used when attempting to clear the above name value pair + //useful for when downloads are being served on a subdomain (e.g. downloads.example.com) + // + cookieDomain: null, + + // + //the title for the popup second window as a download is processing in the case of a mobile browser + // + popupWindowTitle: "Initiating file download...", + + // + //Functionality to encode HTML entities for a POST, need this if data is an object with properties whose values contains strings with quotation marks. + //HTML entity encoding is done by replacing all &,<,>,',",\r,\n characters. + //Note that some browsers will POST the string htmlentity-encoded whilst others will decode it before POSTing. + //It is recommended that on the server, htmlentity decoding is done irrespective. + // + encodeHTMLEntities: true + + }, options); + + var deferred = new $.Deferred(); + + //Setup mobile browser detection: Partial credit: http://detectmobilebrowser.com/ + var userAgent = (navigator.userAgent || navigator.vendor || window.opera).toLowerCase(); + + var isIos; //has full support of features in iOS 4.0+, uses a new window to accomplish this. + var isAndroid; //has full support of GET features in 4.0+ by using a new window. Non-GET is completely unsupported by the browser. See above for specifying a message. + var isOtherMobileBrowser; //there is no way to reliably guess here so all other mobile devices will GET and POST to the current window. + + if (/ip(ad|hone|od)/.test(userAgent)) { + + isIos = true; + + } else if (userAgent.indexOf('android') !== -1) { + + isAndroid = true; + + } else { + + isOtherMobileBrowser = /avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|playbook|silk|iemobile|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(userAgent) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(userAgent.substr(0, 4)); + + } + + var httpMethodUpper = settings.httpMethod.toUpperCase(); + + if (isAndroid && httpMethodUpper !== "GET" && settings.androidPostUnsupportedMessageHtml) { + //the stock android browser straight up doesn't support file downloads initiated by non GET requests: http://code.google.com/p/android/issues/detail?id=1780 + + if ($().dialog) { + $("
").html(settings.androidPostUnsupportedMessageHtml).dialog(settings.dialogOptions); + } else { + alert(settings.androidPostUnsupportedMessageHtml); + } + + return deferred.reject(); + } + + var $preparingDialog = null; + + var internalCallbacks = { + + onPrepare: function (url) { + + //wire up a jquery dialog to display the preparing message if specified + if (settings.preparingMessageHtml) { + + $preparingDialog = $("
").html(settings.preparingMessageHtml).dialog(settings.dialogOptions); + + } else if (settings.prepareCallback) { + + settings.prepareCallback(url); + + } + + }, + + onSuccess: function (url) { + + //remove the perparing message if it was specified + if ($preparingDialog) { + $preparingDialog.dialog('close'); + } + + settings.successCallback(url); + + deferred.resolve(url); + }, + + onAbort: function (url) { + + //remove the perparing message if it was specified + if ($preparingDialog) { + $preparingDialog.dialog('close'); + }; + + settings.abortCallback(url); + + deferred.reject(url); + }, + + onFail: function (responseHtml, url, error) { + + //remove the perparing message if it was specified + if ($preparingDialog) { + $preparingDialog.dialog('close'); + } + + //wire up a jquery dialog to display the fail message if specified + if (settings.failMessageHtml) { + $("
").html(settings.failMessageHtml).dialog(settings.dialogOptions); + } + + settings.failCallback(responseHtml, url, error); + + deferred.reject(responseHtml, url); + } + }; + + internalCallbacks.onPrepare(fileUrl); + + //make settings.data a param string if it exists and isn't already + if (settings.data !== null && typeof settings.data !== "string") { + settings.data = $.param(settings.data); + } + + + var $iframe, + downloadWindow, + formDoc, + $form; + + if (httpMethodUpper === "GET") { + + if (settings.data !== null) { + //need to merge any fileUrl params with the data object + + var qsStart = fileUrl.indexOf('?'); + + if (qsStart !== -1) { + //we have a querystring in the url + + if (fileUrl.substring(fileUrl.length - 1) !== "&") { + fileUrl = fileUrl + "&"; + } + } else { + + fileUrl = fileUrl + "?"; + } + + fileUrl = fileUrl + settings.data; + } + + if (isIos || isAndroid) { + + downloadWindow = window.open(fileUrl); + downloadWindow.document.title = settings.popupWindowTitle; + window.focus(); + + } else if (isOtherMobileBrowser) { + + window.location(fileUrl); + + } else { + + //create a temporary iframe that is used to request the fileUrl as a GET request + $iframe = $("").appendTo("body"); + } + + } else { + + var formInnerHtml = ""; + + if (settings.data !== null) { + + $.each(settings.data.replace(/\+/g, ' ').split("&"), function () { + + var kvp = this.split("="); + + //Issue: When value contains sign '=' then the kvp array does have more than 2 items. We have to join value back + var k = kvp[0]; + kvp.shift(); + var v = kvp.join("="); + kvp = [k, v]; + + var key = settings.encodeHTMLEntities ? htmlSpecialCharsEntityEncode(decodeURIComponent(kvp[0])) : decodeURIComponent(kvp[0]); + if (key) { + var value = settings.encodeHTMLEntities ? htmlSpecialCharsEntityEncode(decodeURIComponent(kvp[1])) : decodeURIComponent(kvp[1]); + formInnerHtml += ''; + } + }); + } + + if (isOtherMobileBrowser) { + + $form = $("
").appendTo("body"); + $form.hide() + .prop('method', settings.httpMethod) + .prop('action', fileUrl) + .html(formInnerHtml); + + } else { + + if (isIos) { + + downloadWindow = window.open("about:blank"); + downloadWindow.document.title = settings.popupWindowTitle; + formDoc = downloadWindow.document; + window.focus(); + + } else { + + $iframe = $("").appendTo("body"); + formDoc = getiframeDocument($iframe); + } + + formDoc.write("" + formInnerHtml + "
" + settings.popupWindowTitle + ""); + $form = $(formDoc).find('form'); + } + + $form.submit(); + } + + + //check if the file download has completed every checkInterval ms + setTimeout(checkFileDownloadComplete, settings.checkInterval); + + + function checkFileDownloadComplete() { + //has the cookie been written due to a file download occuring? + + var cookieValue = settings.cookieValue; + if(typeof cookieValue == 'string') { + cookieValue = cookieValue.toLowerCase(); + } + + var lowerCaseCookie = settings.cookieName.toLowerCase() + "=" + cookieValue; + + if (document.cookie.toLowerCase().indexOf(lowerCaseCookie) > -1) { + + //execute specified callback + internalCallbacks.onSuccess(fileUrl); + + //remove cookie + var cookieData = settings.cookieName + "=; path=" + settings.cookiePath + "; expires=" + new Date(0).toUTCString() + ";"; + if (settings.cookieDomain) cookieData += " domain=" + settings.cookieDomain + ";"; + document.cookie = cookieData; + + //remove iframe + cleanUp(false); + + return; + } + + //has an error occured? + //if neither containers exist below then the file download is occuring on the current window + if (downloadWindow || $iframe) { + + //has an error occured? + try { + + var formDoc = downloadWindow ? downloadWindow.document : getiframeDocument($iframe); + + if (formDoc && formDoc.body !== null && formDoc.body.innerHTML.length) { + + var isFailure = true; + + if ($form && $form.length) { + var $contents = $(formDoc.body).contents().first(); + + try { + if ($contents.length && $contents[0] === $form[0]) { + isFailure = false; + } + } catch (e) { + if (e && e.number == -2146828218) { + // IE 8-10 throw a permission denied after the form reloads on the "$contents[0] === $form[0]" comparison + isFailure = true; + } else { + throw e; + } + } + } + + if (isFailure) { + // IE 8-10 don't always have the full content available right away, they need a litle bit to finish + setTimeout(function () { + internalCallbacks.onFail(formDoc.body.innerHTML, fileUrl); + cleanUp(true); + }, 100); + + return; + } + } + } + catch (err) { + + //500 error less than IE9 + internalCallbacks.onFail('', fileUrl, err); + + cleanUp(true); + + return; + } + } + + + //keep checking... + setTimeout(checkFileDownloadComplete, settings.checkInterval); + } + + //gets an iframes document in a cross browser compatible manner + function getiframeDocument($iframe) { + var iframeDoc = $iframe[0].contentWindow || $iframe[0].contentDocument; + if (iframeDoc.document) { + iframeDoc = iframeDoc.document; + } + return iframeDoc; + } + + function cleanUp(isFailure) { + + setTimeout(function() { + + if (downloadWindow) { + + if (isAndroid) { + downloadWindow.close(); + } + + if (isIos) { + if (downloadWindow.focus) { + downloadWindow.focus(); //ios safari bug doesn't allow a window to be closed unless it is focused + if (isFailure) { + downloadWindow.close(); + } + } + } + } + + //iframe cleanup appears to randomly cause the download to fail + //not doing it seems better than failure... + //if ($iframe) { + // $iframe.remove(); + //} + + }, 0); + } + + + function htmlSpecialCharsEntityEncode(str) { + return str.replace(htmlSpecialCharsRegEx, function(match) { + return '&' + htmlSpecialCharsPlaceHolders[match]; + }); + } + var promise = deferred.promise(); + promise.abort = function() { + cleanUp(); + $iframe.attr('src', '').html(''); + internalCallbacks.onAbort(fileUrl); + }; + return promise; + } +}); + +})(jQuery, this || window); \ No newline at end of file diff --git a/public/javascripts/download/jquery.fileDownload.min.js b/public/javascripts/download/jquery.fileDownload.min.js new file mode 100644 index 000000000..c4ae8b923 --- /dev/null +++ b/public/javascripts/download/jquery.fileDownload.min.js @@ -0,0 +1 @@ +!function(e,o){var t=/[<>&\r\n"']/gm,a={"<":"lt;",">":"gt;","&":"amp;","\r":"#13;","\n":"#10;",'"':"quot;","'":"#39;"};e.extend({fileDownload:function(i,n){var r,l,c,d=e.extend({preparingMessageHtml:null,failMessageHtml:null,androidPostUnsupportedMessageHtml:"Unfortunately your Android browser doesn't support this type of file download. Please try again with a different browser.",dialogOptions:{modal:!0},prepareCallback:function(e){},successCallback:function(e){},abortCallback:function(e){},failCallback:function(e,o,t){},httpMethod:"GET",data:null,checkInterval:100,cookieName:"fileDownload",cookieValue:"true",cookiePath:"/",cookieDomain:null,popupWindowTitle:"Initiating file download...",encodeHTMLEntities:!0},n),s=new e.Deferred,p=(navigator.userAgent||navigator.vendor||o.opera).toLowerCase();/ip(ad|hone|od)/.test(p)?r=!0:-1!==p.indexOf("android")?l=!0:c=/avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|playbook|silk|iemobile|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(p)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|e\-|e\/|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(di|rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|xda(\-|2|g)|yas\-|your|zeto|zte\-/i.test(p.substr(0,4));var m=d.httpMethod.toUpperCase();if(l&&"GET"!==m&&d.androidPostUnsupportedMessageHtml)return e().dialog?e("
").html(d.androidPostUnsupportedMessageHtml).dialog(d.dialogOptions):alert(d.androidPostUnsupportedMessageHtml),s.reject();var u,f,g,h,b=null,k={onPrepare:function(o){d.preparingMessageHtml?b=e("
").html(d.preparingMessageHtml).dialog(d.dialogOptions):d.prepareCallback&&d.prepareCallback(o)},onSuccess:function(e){b&&b.dialog("close"),d.successCallback(e),s.resolve(e)},onAbort:function(e){b&&b.dialog("close"),d.abortCallback(e),s.reject(e)},onFail:function(o,t,a){b&&b.dialog("close"),d.failMessageHtml&&e("
").html(d.failMessageHtml).dialog(d.dialogOptions),d.failCallback(o,t,a),s.reject(o,t)}};if(k.onPrepare(i),null!==d.data&&"string"!=typeof d.data&&(d.data=e.param(d.data)),"GET"===m){if(null!==d.data)-1!==i.indexOf("?")?"&"!==i.substring(i.length-1)&&(i+="&"):i+="?",i+=d.data;r||l?((f=o.open(i)).document.title=d.popupWindowTitle,o.focus()):c?o.location(i):u=e("").appendTo("body")}else{var v="";null!==d.data&&e.each(d.data.replace(/\+/g," ").split("&"),function(){var e=this.split("="),o=e[0];e.shift(),e=[o,e.join("=")];var t=d.encodeHTMLEntities?T(decodeURIComponent(e[0])):decodeURIComponent(e[0]);if(t){var a=d.encodeHTMLEntities?T(decodeURIComponent(e[1])):decodeURIComponent(e[1]);v+=''}}),c?(h=e("
").appendTo("body")).hide().prop("method",d.httpMethod).prop("action",i).html(v):(r?((f=o.open("about:blank")).document.title=d.popupWindowTitle,g=f.document,o.focus()):g=w(u=e("").appendTo("body")),g.write(""+v+"
"+d.popupWindowTitle+""),h=e(g).find("form")),h.submit()}function w(e){var o=e[0].contentWindow||e[0].contentDocument;return o.document&&(o=o.document),o}function y(e){setTimeout(function(){f&&(l&&f.close(),r&&f.focus&&(f.focus(),e&&f.close()))},0)}function T(e){return e.replace(t,function(e){return"&"+a[e]})}setTimeout(function o(){var t=d.cookieValue;"string"==typeof t&&(t=t.toLowerCase());var a=d.cookieName.toLowerCase()+"="+t;if(document.cookie.toLowerCase().indexOf(a)>-1){k.onSuccess(i);var n=d.cookieName+"=; path="+d.cookiePath+"; expires="+new Date(0).toUTCString()+";";return d.cookieDomain&&(n+=" domain="+d.cookieDomain+";"),document.cookie=n,void y(!1)}if(f||u)try{var r=f?f.document:w(u);if(r&&null!==r.body&&r.body.innerHTML.length){var l=!0;if(h&&h.length){var c=e(r.body).contents().first();try{c.length&&c[0]===h[0]&&(l=!1)}catch(e){if(!e||-2146828218!=e.number)throw e;l=!0}}if(l)return void setTimeout(function(){k.onFail(r.body.innerHTML,i),y(!0)},100)}}catch(e){return k.onFail("",i,e),void y(!0)}setTimeout(o,d.checkInterval)},d.checkInterval);var x=s.promise();return x.abort=function(){y(),u.attr("src","").html(""),k.onAbort(i)},x}})}(jQuery,this||window); \ No newline at end of file diff --git a/public/react/public/css/edu-all.css b/public/react/public/css/edu-all.css index a9e24da3d..fad3568b4 100644 --- a/public/react/public/css/edu-all.css +++ b/public/react/public/css/edu-all.css @@ -1,11 +1,25 @@ /*--------------------------首页*/ /*头部导航条样式---2018-03-19--by-cs*/ -.newHeader{background: #24292D !important; width:100%; height: 60px !important; min-width: 1200px;position: fixed;top: 0px;left: 0px;z-index:1000;-moz-box-shadow: 0px 0px 12px rgba(0,0,0,0.1); /* 老的 Firefox */box-shadow: 0px 0px 12px rgba(0,0,0,0.1);} +.newHeader{ + /*overflow:hidden;*/ + /*text-overflow:ellipsis;*/ + /*white-space:nowrap;*/ + background: #24292D !important; width:100%; height: 60px !important; min-width: 1200px;position: fixed;top: 0px;left: 0px;z-index:1000;-moz-box-shadow: 0px 0px 12px rgba(0,0,0,0.1); /* 老的 Firefox */box-shadow: 0px 0px 12px rgba(0,0,0,0.1); +} .newHeader .logoimg{ margin-top: 16px; float: left; width: 97px;} -.head-nav{float: left;width: 830px;text-align: center;height: 60px;box-sizing: border-box; min-width: 400px;} +.head-nav{ + float: left; + text-align: center; + height: 60px; + box-sizing: border-box; + min-width: 785px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} .head-nav ul#header-nav{position: absolute;top: 0px;z-index: 3;height: 60px;box-sizing: border-box;} .head-nav ul#header-nav li{float: left;height: 60px;line-height: 60px;margin-right: 30px;cursor: pointer;position: relative;font-size: 16px} .head-nav ul#header-nav li a{display: block;height: 100%;width: 100%;color: #fff} @@ -406,7 +420,7 @@ table.text-file{} /*-------------------------------实训路径-------------------------------*/ -.path-head{width: 100%;height: 300px;background-image: url("/images/educoder/path.jpg");background-color: #081C4B;background-size: 100% 100%;} +.path-head{width: 100%;height: 300px;background-image: url("/images/educoder/path.png");background-color: #081C4B;background-size: 100% 100%;} .pathNavLine{position: absolute;bottom: -8px;width: 100%;} .path-nav li{float: left;padding: 0px 30px;height: 42px;} .path-nav li a{color:#fff;font-size: 16px;display: block; height: 40px;} diff --git a/public/react/public/index.html b/public/react/public/index.html index a4a795941..801189edb 100755 --- a/public/react/public/index.html +++ b/public/react/public/index.html @@ -87,7 +87,7 @@ -
+
diff --git a/public/react/src/App.js b/public/react/src/App.js index 49dac07cd..e713cd0fd 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -226,6 +226,12 @@ const Interestpage = Loadable({ loading: Loading, }) +//众包创新 +const ProjectPackages=Loadable({ + loader: () => import('./modules/projectPackages/ProjectPackageIndex'), + loading: Loading, +}) + class App extends Component { constructor(props) { super(props) @@ -296,6 +302,9 @@ class App extends Component { {/**/} + + {/*众包创新*/} + {/*认证*/} diff --git a/public/react/src/common/TextUtil.js b/public/react/src/common/TextUtil.js index 82a848cac..bb0b3f145 100644 --- a/public/react/src/common/TextUtil.js +++ b/public/react/src/common/TextUtil.js @@ -1,4 +1,6 @@ -import { bytesToSize } from 'educoder'; +import { bytesToSize, getUrl2 } from 'educoder'; +const $ = window.$ + export function isImageExtension(fileName) { return fileName ? !!(fileName.match(/.(jpg|jpeg|png|gif)$/i)) : false } @@ -10,7 +12,8 @@ export function markdownToHTML(oldContent, selector) { window.$(selector).html(oldContent) } else { try { - var markdwonParser = window.editormd.markdownToHTML("md_div", { + // selector || + var markdwonParser = window.editormd.markdownToHTML(selector || "md_div", { markdown: oldContent, // .replace(/▁/g,"▁▁▁"), emoji: true, htmlDecode: "style,script,iframe", // you can filter tags decode @@ -23,6 +26,10 @@ export function markdownToHTML(oldContent, selector) { } catch(e) { console.error(e) } + // selector = '.' + selector + if (selector) { + return; + } const content = window.$('#md_div').html() if (selector) { @@ -31,6 +38,25 @@ export function markdownToHTML(oldContent, selector) { return content } } +function _doDownload(options) { + $.fileDownload("/api" + options.url, { + successCallback: options.successCallback, + failCallback: options.failCallback + }); +} +export function downloadFile(options) { + if ($.fileDownload) { + _doDownload(options) + } else { + const _url_origin = getUrl2() + $.getScript( + `${_url_origin}/javascripts/download/jquery.fileDownload.min.js`, + (data, textStatus, jqxhr) => { + _doDownload(options) + }); + } + +} export function appendFileSizeToUploadFile(item) { return `${item.title}${uploadNameSizeSeperator}${item.filesize}` diff --git a/public/react/src/common/components/markdown/MarkdownToHtml.css b/public/react/src/common/components/markdown/MarkdownToHtml.css new file mode 100644 index 000000000..affba12cd --- /dev/null +++ b/public/react/src/common/components/markdown/MarkdownToHtml.css @@ -0,0 +1,6 @@ +.markdownToHtml.editormd-html-preview, .markdownToHtml.editormd-preview-container { + overflow: hidden; +} +.markdownToHtml.editormd-html-preview p.editormd-tex, .markdownToHtml.editormd-preview-container p.editormd-tex { + text-align: left; +} \ No newline at end of file diff --git a/public/react/src/common/components/markdown/MarkdownToHtml.js b/public/react/src/common/components/markdown/MarkdownToHtml.js index 0780fc789..63733165e 100644 --- a/public/react/src/common/components/markdown/MarkdownToHtml.js +++ b/public/react/src/common/components/markdown/MarkdownToHtml.js @@ -1,8 +1,8 @@ import React,{ Component } from "react"; import { markdownToHTML } from 'educoder' +import './MarkdownToHtml.css' /** selector 需要传入唯一的selector作为id,不然会引起冲突 - delay 如果有公式,需要传入delay={true} */ class MarkdownToHtml extends Component{ constructor(props){ @@ -10,33 +10,26 @@ class MarkdownToHtml extends Component{ this.state={ } } - _markdownToHTML = (content, selector) => { - if (this.props.delay == true) { - (function(content, selector) { - // console.log('selector: ', selector) - setTimeout(() => { - markdownToHTML(content, selector) - }, 600) - })(content, selector) - } else { - markdownToHTML(content, selector) - } + _markdownToHTML = (content, selector) => { + markdownToHTML(content, selector) } componentDidUpdate = (prevProps) => { if (this.props.content) { if ( prevProps.content != this.props.content ) { - this._markdownToHTML(this.props.content, `.markdown_to_html_${this.props.selector || ''}`) + this._markdownToHTML(this.props.content, `markdown_to_html_${this.props.selector || ''}`) } } } componentDidMount () { - this.props.content && this._markdownToHTML(this.props.content, `.markdown_to_html_${this.props.selector || ''}`) + this.props.content && this._markdownToHTML(this.props.content, `markdown_to_html_${this.props.selector || ''}`) } render(){ const { style, className } = this.props + let _selector = `markdown_to_html_${this.props.selector || ''}` + return( -
diff --git a/public/react/src/common/educoder.js b/public/react/src/common/educoder.js index f090d2c39..44b3057cc 100644 --- a/public/react/src/common/educoder.js +++ b/public/react/src/common/educoder.js @@ -15,7 +15,8 @@ export { updatePageParams as updatePageParams } from './RouterUti export { bytesToSize as bytesToSize } from './UnitUtil'; -export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension } from './TextUtil' +export { markdownToHTML, uploadNameSizeSeperator, appendFileSizeToUploadFile, appendFileSizeToUploadFileAll, isImageExtension, + downloadFile } from './TextUtil' export { handleDateString, getNextHalfHourOfMoment,formatDuring } from './DateUtil' diff --git a/public/react/src/modules/courses/ListPageIndex.js b/public/react/src/modules/courses/ListPageIndex.js index 95342bb13..9f12f6434 100644 --- a/public/react/src/modules/courses/ListPageIndex.js +++ b/public/react/src/modules/courses/ListPageIndex.js @@ -103,7 +103,7 @@ class ListPageIndex extends Component{
{/*头部banner*/} - + {/*{yslGuideone===null||yslGuideone===undefined||yslGuideone===false?*/} {/* (*/} {/* this.props.isAdmin()===true?*/} diff --git a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js index ff8e3e3a2..b8a5d450c 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkDetailIndex.js @@ -8,7 +8,7 @@ import { CNotificationHOC } from '../common/CNotificationHOC' import { RouteHOC } from './common' import locale from 'antd/lib/date-picker/locale/zh_CN'; -import { WordsBtn, MarkdownToHtml, trigger, queryString } from 'educoder'; +import { WordsBtn, MarkdownToHtml, trigger, queryString, downloadFile } from 'educoder'; import axios from 'axios'; import Modals from '../../modals/Modals'; import CoursesListType from '../coursesPublic/CoursesListType'; @@ -18,6 +18,8 @@ import '../css/Courses.css' import CBreadcrumb from '../common/CBreadcrumb' import DownloadMessageysl from "../../modals/DownloadMessageysl"; +import { Spin } from 'antd' + //引入对应跳转的组件 //新建分组/普通作业 @@ -64,6 +66,7 @@ class CommonWorkDetailIndex extends Component{ this.state = { DownloadType:false, DownloadMessageval:undefined, + donwloading:false, } } initWorkDetailCommonState = (data) => { @@ -103,7 +106,10 @@ class CommonWorkDetailIndex extends Component{ /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url+ '&export=true').then((response) => { + if(response===undefined){ + return + } if(response.data.status&&response.data.status===-1){ }else if(response.data.status&&response.data.status===-2){ @@ -123,7 +129,20 @@ class CommonWorkDetailIndex extends Component{ } }else { this.props.showNotification(`正在下载中`); - window.open("/api"+url, '_blank'); + + this.setState({ donwloading: true }) + downloadFile({ + url: url, + successCallback: (url) => { + this.setState({ donwloading: false }) + console.log('successCallback') + }, + failCallback: (responseHtml, url) => { + this.setState({ donwloading: false }) + console.log('failCallback') + } + }) + // window.open("/api"+url, '_blank'); } }).catch((error) => { console.log(error) @@ -136,7 +155,7 @@ class CommonWorkDetailIndex extends Component{ DownloadMessageval:undefined }) } - + bindRef = ref => { this.child = ref }; render() { @@ -171,8 +190,12 @@ class CommonWorkDetailIndex extends Component{ let params = {} if (isListModule) { // TODO - // params = this.refs.commonWorkList._getRequestParams() + if(this.child!=undefined) { + params = this.child._getRequestParams() !== undefined ? this.child._getRequestParams() : {}; + } } + // console.log("普通作业176176176"); + // console.log(params); let exportUrl = `/homework_commons/${workId}/works_list.zip?${queryString.stringify(params)}` let exportResultUrl = `/homework_commons/${workId}/works_list.xlsx?${queryString.stringify(params)}` return ( @@ -244,7 +267,7 @@ class CommonWorkDetailIndex extends Component{ }
- { noTab !== true &&
+ { noTab !== true &&
this.setState({moduleName: '作品列表'})} @@ -283,18 +306,30 @@ class CommonWorkDetailIndex extends Component{ padding-top: 10px; padding-bottom: 8px; } + + .floatSpinParent .ant-spin-nested-loading { + float: right; + } `} - {this.props.isAdmin()?
  • + {this.props.isAdmin()? +
  • 导出 -
  • :""} + + :""} {/* {isAdmin && 导出作品附件} {isAdmin && 导出成绩} */} @@ -356,7 +391,7 @@ class CommonWorkDetailIndex extends Component{ {/* 作品列表 */} () + (props) => () } > @@ -382,7 +417,7 @@ class CommonWorkDetailIndex extends Component{ {/* 作品列表 */} () + (props) => () } > diff --git a/public/react/src/modules/courses/busyWork/CommonWorkList.js b/public/react/src/modules/courses/busyWork/CommonWorkList.js index 5938d037a..9224e7eb2 100644 --- a/public/react/src/modules/courses/busyWork/CommonWorkList.js +++ b/public/react/src/modules/courses/busyWork/CommonWorkList.js @@ -400,7 +400,12 @@ class CommonWorkList extends Component{ componentDidMount() { this.fetchList() on('commonwork_fetch_all', this.fetchAllListener) - $("html").animate({ scrollTop: $('html').scrollTop() - 100 }) + $("html").animate({ scrollTop: $('html').scrollTop() - 100 }); + try { + this.props.triggerRef(this); + }catch (e) { + + } } componentWillUnmount() { @@ -420,7 +425,8 @@ class CommonWorkList extends Component{ teacher_comment: arg_teacher_comment.length == 0 ? '' : arg_teacher_comment[0], order, limit: PAGE_SIZE, - b_order: orderMap[order] + b_order: orderMap[order], + group_id:arg_course_group, } } fetchList = () => { @@ -767,7 +773,7 @@ class CommonWorkList extends Component{
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/react/src/modules/courses/busyWork/common/TabRightComponents.js b/public/react/src/modules/courses/busyWork/common/TabRightComponents.js index a070ba69a..5320dd0ca 100644 --- a/public/react/src/modules/courses/busyWork/common/TabRightComponents.js +++ b/public/react/src/modules/courses/busyWork/common/TabRightComponents.js @@ -44,7 +44,7 @@ class TabRightComponents extends Component{ } /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true' ).then((response) => { if(response.data.status&&response.data.status===-1){ }else if(response.data.status&&response.data.status===-2){ diff --git a/public/react/src/modules/courses/exercise/ExerciseDisplay.js b/public/react/src/modules/courses/exercise/ExerciseDisplay.js index bd70bece6..a0296476f 100644 --- a/public/react/src/modules/courses/exercise/ExerciseDisplay.js +++ b/public/react/src/modules/courses/exercise/ExerciseDisplay.js @@ -33,6 +33,21 @@ class ExerciseDisplay extends Component{ this.state = { exercise_questions: [], + exercise_group_id:[], + page:1, + limit:10, + searchtext:"", + order: "end_at", + } + } + _getRequestParams() { + const { order, exercise_group_id,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + order, + limit: limit, + group_id:exercise_group_id, } } componentDidMount = () => { @@ -49,6 +64,21 @@ class ExerciseDisplay extends Component{ console.log(error); }); } + try { + this.props.triggerRef(this); + }catch (e) { + + } + } + _getRequestParams() { + const { order, exercise_group_id,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + order, + limit: limit, + group_id:exercise_group_id, + } } render() { // let { question_title, question_score, question_type, question_choices, standard_answer, diff --git a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js index cd3355082..778829d72 100644 --- a/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js +++ b/public/react/src/modules/courses/exercise/ExerciseReviewAndAnswer.js @@ -7,7 +7,7 @@ import '../poll/pollStyle.css' import '../css/Courses.css' import moment from 'moment' -import { WordsBtn,markdownToHTML,ActionBtn,getImageUrl } from 'educoder' +import { WordsBtn,markdownToHTML,ActionBtn,getImageUrl, MarkdownToHtml } from 'educoder' import Modals from '../../modals/Modals' import CoursesListType from '../coursesPublic/CoursesListType'; @@ -537,7 +537,7 @@ class ExerciseReviewAndAnswer extends Component{ />

    - {courseName} + {courseName} > {data && data.left_banner_name} > @@ -712,7 +712,10 @@ class ExerciseReviewAndAnswer extends Component{

  • -

    + {/*

    */} +
  • { // 选择题和判断题共用 @@ -724,6 +727,7 @@ class ExerciseReviewAndAnswer extends Component{ questionType={item} user_exercise_status={user_exercise_status} changeQuestionStatus={(No,flag)=>this.changeQuestionStatus(No,flag)} + index={key} > } { @@ -736,6 +740,8 @@ class ExerciseReviewAndAnswer extends Component{ questionType={item} user_exercise_status={user_exercise_status} changeQuestionStatus={(No,flag)=>this.changeQuestionStatus(No,flag)} + index={key} + > } { @@ -748,6 +754,8 @@ class ExerciseReviewAndAnswer extends Component{ questionType={item} user_exercise_status={user_exercise_status} changeQuestionStatus={(No,flag)=>this.changeQuestionStatus(No,flag)} + index={key} + > } { @@ -774,6 +782,8 @@ class ExerciseReviewAndAnswer extends Component{ questionType={item} user_exercise_status={user_exercise_status} id={this.state.Id} + index={key} + > } diff --git a/public/react/src/modules/courses/exercise/Exercisesetting.js b/public/react/src/modules/courses/exercise/Exercisesetting.js index 06269244d..9b6103fdb 100644 --- a/public/react/src/modules/courses/exercise/Exercisesetting.js +++ b/public/react/src/modules/courses/exercise/Exercisesetting.js @@ -63,17 +63,46 @@ class Exercisesetting extends Component{ choice_random:true, time:0, publish_timetype:false, - end_timetype:false + end_timetype:false, + exercise_group_id:[], + page:1, + limit:10, + searchtext:"", + order: "end_at", } console.log("Exercisesetting"); console.log("69"); console.log(props); } - + _getRequestParams() { + const { order, exercise_group_id,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + order, + limit: limit, + group_id:exercise_group_id, + } + } //加载 componentDidMount=()=>{ this.getSettingInfo(); // window.addEventListener('click', this.handleClick); + try { + this.props.triggerRef(this); + }catch (e) { + + } + } + _getRequestParams() { + const { order, exercise_group_id,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + order, + limit: limit, + group_id:exercise_group_id, + } } // handleClick=(e)=>{ diff --git a/public/react/src/modules/courses/exercise/Exercisestatisticalresult.js b/public/react/src/modules/courses/exercise/Exercisestatisticalresult.js index 6e7b52715..34f32b234 100644 --- a/public/react/src/modules/courses/exercise/Exercisestatisticalresult.js +++ b/public/react/src/modules/courses/exercise/Exercisestatisticalresult.js @@ -1,5 +1,5 @@ import React, {Component} from "react"; -import {WordsBtn,markdownToHTML} from 'educoder'; +import {WordsBtn,markdownToHTML, MarkdownToHtml} from 'educoder'; import { Form, Select, Input, Button,Checkbox,Upload,Icon,message,Modal, Table, Divider,InputNumber, Tag,DatePicker,Radio,Tooltip,Pagination} from "antd"; import {Link,Switch,Route,Redirect} from 'react-router-dom'; import axios from 'axios'; @@ -23,15 +23,32 @@ class Exercisestatisticalresult extends Component { exercise_group_id:[], page:1, limit:10, + searchtext:"", + order: "end_at", + } } componentDidMount() { let{sort,exercise_group_id,page,limit}=this.state; - this.updatefun(sort,exercise_group_id,page,limit) - } + this.updatefun(sort,exercise_group_id,page,limit); + try { + this.props.triggerRef(this); + }catch (e) { + } + } + _getRequestParams() { + const { order, exercise_group_id,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + order, + limit: limit, + group_id:exercise_group_id, + } + } updatefun=(sort,exercise_group_id,page,limit)=>{ let ExerciseId=this.props.match.params.Id; let url = `/exercises/`+ExerciseId+`/exercise_result.json`; @@ -194,8 +211,10 @@ class Exercisestatisticalresult extends Component { {item.ques_position+"."}{item.ques_type===0?"单选":item.ques_type===1?"多选":item.ques_type===2?"判断":item.ques_type===3?"填空":item.ques_type===4?"主观":item.ques_type===5?"实训":""}题
    {/*Q{item.ques_position}:*/} -
    - + {/*
    */} + {/**/}
    diff --git a/public/react/src/modules/courses/exercise/Exercisetablesmubu.js b/public/react/src/modules/courses/exercise/Exercisetablesmubu.js index 60c29ffbc..92cfa30b7 100644 --- a/public/react/src/modules/courses/exercise/Exercisetablesmubu.js +++ b/public/react/src/modules/courses/exercise/Exercisetablesmubu.js @@ -52,7 +52,7 @@ class Exercisetablesmubus extends Component { dataIndex: 'commit_percent', key: 'commit_percent', render: (text, record, index) => { - const _content = + const _content = {text.value!="有效填写量"&&text.value!="wrong" && } diff --git a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js index 6f4cec877..f7a989f79 100644 --- a/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js +++ b/public/react/src/modules/courses/exercise/Studentshavecompletedthelist.js @@ -1213,6 +1213,11 @@ class Studentshavecompletedthelist extends Component { // console.log("2222222222222"); // console.log(this.props.isAdmin()); // } + try { + this.props.triggerRef(this); + }catch (e) { + + } } componentWillReceiveProps = (nextProps) => { @@ -1384,7 +1389,8 @@ class Studentshavecompletedthelist extends Component { loadingstate: true, }) } - + console.log(response); + console.log(1393); thiss.Generatenewdatasy(response.data.exercise_users, response); } }).catch((error) => { @@ -1984,9 +1990,14 @@ class Studentshavecompletedthelist extends Component { }).then((response) => { // console.log("528"); // console.log(JSON.stringify(response)); + if(response===undefined){ + return + } this.setState({ loadingstate: false, }) + console.log(response); + console.log(1997); this.Generatenewdatasy(response.data.exercise_users, response); }).catch((error) => { console.log(error) @@ -2279,22 +2290,8 @@ class Studentshavecompletedthelist extends Component { this.Searchdatasys(this.state.order, this.state.commit_status, this.state.review, this.state.checkedValuesineinfo, this.state.searchtext, 1, this.state.limit); } - } - //搜索学生 文字输入 - inputSearchValues = (e) => { - // console.log(e.target.value) - if (e.target.value === "") { - this.setState({ - searchtext: undefined, - }) - } else { - this.setState({ - searchtext: e.target.value, - }) - } - - } - //搜索学生按钮输入 + }; + //搜索学生按钮输入 老师 searchValues = (value) => { //点击直接搜索 // if(value === ""){ @@ -2313,8 +2310,34 @@ class Studentshavecompletedthelist extends Component { // console.log(value) + }; + _getRequestParams() { + const { order, checkedValuesineinfo,searchtext, page ,limit} = this.state + return { + page, + search:searchtext, + group_id:checkedValuesineinfo, + limit: limit, + order, + } } + //搜索学生 文字输入 + inputSearchValues = (e) => { + // console.log(e.target.value) + if (e.target.value === "") { + this.setState({ + searchtext: undefined, + }) + } else { + this.setState({ + searchtext: e.target.value, + }) + } + + }; + + //排序 funordersy = (e) => { if (e === "end_at") { @@ -2565,7 +2588,7 @@ class Studentshavecompletedthelist extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    @@ -2630,7 +2653,7 @@ class Studentshavecompletedthelist extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    @@ -2692,7 +2715,7 @@ class Studentshavecompletedthelist extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js b/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js index ddb448cfc..33f93c676 100644 --- a/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js +++ b/public/react/src/modules/courses/exercise/Testpapersettinghomepage.js @@ -1,7 +1,7 @@ import React,{ Component } from "react"; import {Checkbox,Input,Table, Pagination,Menu} from "antd"; import {Link,NavLink} from 'react-router-dom'; -import { WordsBtn ,ActionBtn} from 'educoder'; +import { WordsBtn ,ActionBtn,queryString} from 'educoder'; import CoursesListType from '../coursesPublic/CoursesListType'; import '../css/members.css'; import '../css/busyWork.css'; @@ -19,7 +19,7 @@ import Ecerciseallbackagain from './Ecerciseallbackagain'; const polls_status={1:"未发布",2:"提交中",3:"已截止",4:"已结束"} const start_Value={0:"继续答题",1:"查看答题",2:"开始答题"} - +const qs = require('qs'); //试卷主要设置页面 class Testpapersettinghomepage extends Component{ constructor(props) { @@ -163,8 +163,17 @@ class Testpapersettinghomepage extends Component{ } /// 确认是否下载 - confirmysl(url){ - axios.get(url).then((response) => { + confirmysl(url,child){ + let params ={} + if(child!=undefined){ + params =child._getRequestParams()!==undefined?child._getRequestParams():{}; + } + console.log("170"); + console.log(params); + axios.get(url+`?${queryString.stringify(params)}`+ '&export=true' ).then((response) => { + if(response===undefined){ + return + } if(response.data.status&&response.data.status===-1){ }else if(response.data.status&&response.data.status===-2){ @@ -184,7 +193,7 @@ class Testpapersettinghomepage extends Component{ } }else { this.props.showNotification(`正在下载中`); - window.open("/api"+url, '_blank'); + window.open("/api"+url+`?${queryString.stringify(params)}`, '_blank'); } }).catch((error) => { console.log(error) @@ -218,6 +227,7 @@ class Testpapersettinghomepage extends Component{ // DownloadMessageval:undefined // }) // } + bindRef = ref => { this.child = ref }; goback=()=>{ // let {datalist}=this.state; // let courseId=this.props.match.params.coursesId; @@ -236,6 +246,7 @@ class Testpapersettinghomepage extends Component{ let {tab,visible,Commonheadofthetestpaper}=this.state; const isAdmin =this.props.isAdmin(); const isStudent = this.props.isStudent(); + // TODO return(
    @@ -267,7 +278,7 @@ class Testpapersettinghomepage extends Component{

    {this.props.coursedata.name} > - 试卷 + 试卷 > 试卷详情

    @@ -345,7 +356,7 @@ class Testpapersettinghomepage extends Component{ {isAdmin === true?
  • 导出 @@ -400,22 +411,22 @@ class Testpapersettinghomepage extends Component{ /> { // 教师列表 - parseInt(tab[0])==0 && this.setcourse_groupysls(value)} current_status = {this.state.current_status}> + parseInt(tab[0])==0 && this.setcourse_groupysls(value)} current_status = {this.state.current_status}> } {/*统计结果*/} { - parseInt(tab[0])==1 && + parseInt(tab[0])==1 && } { - parseInt(tab[0])==2 && + parseInt(tab[0])==2 && } { - parseInt(tab[0])==3 && + parseInt(tab[0])==3 && }
  • diff --git a/public/react/src/modules/courses/exercise/new/JudgeDisplay.js b/public/react/src/modules/courses/exercise/new/JudgeDisplay.js index 7beaa50e5..60fbd5ac2 100644 --- a/public/react/src/modules/courses/exercise/new/JudgeDisplay.js +++ b/public/react/src/modules/courses/exercise/new/JudgeDisplay.js @@ -7,7 +7,7 @@ import { } from 'antd'; import axios from 'axios' import { qNameArray } from './common' -import {getUrl, ActionBtn, markdownToHTML} from 'educoder'; +import {getUrl, ActionBtn, markdownToHTML, MarkdownToHtml } from 'educoder'; import QestionDisplayHeader from './QestionDisplayHeader' const { TextArea } = Input; const confirm = Modal.confirm; @@ -87,9 +87,12 @@ class JudgeDisplay extends Component{ return (
    - {item.choice_text} + {/* {item.choice_text} */} + {/* */} + dangerouslySetInnerHTML={{__html: markdownToHTML1(item.choice_text)}}> */}
    ) })} diff --git a/public/react/src/modules/courses/exercise/new/MainDisplay.js b/public/react/src/modules/courses/exercise/new/MainDisplay.js index 0581865d7..44a795374 100644 --- a/public/react/src/modules/courses/exercise/new/MainDisplay.js +++ b/public/react/src/modules/courses/exercise/new/MainDisplay.js @@ -70,10 +70,10 @@ class MainDisplay extends Component{
    参考答案:
    {/*
    */} diff --git a/public/react/src/modules/courses/exercise/new/NullDisplay.js b/public/react/src/modules/courses/exercise/new/NullDisplay.js index eade97474..079b1194f 100644 --- a/public/react/src/modules/courses/exercise/new/NullDisplay.js +++ b/public/react/src/modules/courses/exercise/new/NullDisplay.js @@ -109,7 +109,7 @@ class NullDisplay extends Component{
    { answers.answer_text.map((item, itemIndex) => { return })} diff --git a/public/react/src/modules/courses/exercise/new/QestionDisplayHeader.js b/public/react/src/modules/courses/exercise/new/QestionDisplayHeader.js index 7b82b14b6..c90d87dac 100644 --- a/public/react/src/modules/courses/exercise/new/QestionDisplayHeader.js +++ b/public/react/src/modules/courses/exercise/new/QestionDisplayHeader.js @@ -82,9 +82,9 @@ class QestionDisplayHeader extends Component{
    { question_title && - //
    } diff --git a/public/react/src/modules/courses/exercise/new/SingleDisplay.js b/public/react/src/modules/courses/exercise/new/SingleDisplay.js index cbb6da827..bce4dc4c1 100644 --- a/public/react/src/modules/courses/exercise/new/SingleDisplay.js +++ b/public/react/src/modules/courses/exercise/new/SingleDisplay.js @@ -101,10 +101,10 @@ class SingleDisplay extends Component{
    {prefix} {/* */} + dangerouslySetInnerHTML={{__html: markdownToHTML1(item.choice_text)}}> */}
    ) } else { @@ -112,10 +112,10 @@ class SingleDisplay extends Component{
    {prefix} {/* */} + dangerouslySetInnerHTML={{__html: markdownToHTML1(item.choice_text)}}> */}
    ) } })} diff --git a/public/react/src/modules/courses/exercise/question/fillEmpty.js b/public/react/src/modules/courses/exercise/question/fillEmpty.js index 79bc164d8..5179432a2 100644 --- a/public/react/src/modules/courses/exercise/question/fillEmpty.js +++ b/public/react/src/modules/courses/exercise/question/fillEmpty.js @@ -1,6 +1,6 @@ import React,{ Component } from "react"; import {Checkbox,Radio, Input} from "antd"; -import {DMDEditor,markdownToHTML } from 'educoder' +import {DMDEditor,markdownToHTML, MarkdownToHtml } from 'educoder' import axios from 'axios' @@ -140,7 +140,10 @@ class fillEmpty extends Component{ { item.answer_text && item.answer_text.map((i,index)=>{ return( -
    + + //
    ) }) } diff --git a/public/react/src/modules/courses/exercise/question/multiple.js b/public/react/src/modules/courses/exercise/question/multiple.js index 3ef3d960f..7e96f8550 100644 --- a/public/react/src/modules/courses/exercise/question/multiple.js +++ b/public/react/src/modules/courses/exercise/question/multiple.js @@ -1,6 +1,6 @@ import React,{ Component } from "react"; import {Checkbox,Radio, Input} from "antd"; -import {markdownToHTML} from 'educoder' +import {markdownToHTML, MarkdownToHtml} from 'educoder' import axios from 'axios' const tagArray = [ @@ -51,7 +51,10 @@ class Multiple extends Component{

    {prefix} {/* */} - + {/* */} +

    ) }) diff --git a/public/react/src/modules/courses/exercise/question/simpleAnswer.js b/public/react/src/modules/courses/exercise/question/simpleAnswer.js index 240f775c2..527044968 100644 --- a/public/react/src/modules/courses/exercise/question/simpleAnswer.js +++ b/public/react/src/modules/courses/exercise/question/simpleAnswer.js @@ -1,6 +1,6 @@ import React,{ Component } from "react"; import {Checkbox,Radio, Input} from "antd"; -import {markdownToHTML} from 'educoder' +import {markdownToHTML, MarkdownToHtml} from 'educoder' import TPMMDEditor from '../../../../modules/tpm/challengesnew/TPMMDEditor' import axios from 'axios' @@ -54,7 +54,10 @@ class simpleAnswer extends Component{
  • { user_exercise_status == 1 ? -
    0 ? questionType.user_answer[0]:"")}}>
    + //
    0 ? questionType.user_answer[0]:"")}}>
    + 0 ? questionType.user_answer[0]:""} selector={'simgle_' + (this.props.index + 1)} + className="answerStyle" + > :
    0 ? questionType.user_answer[0]:''} mdID={'simpleEditor'+questionType.question_id} placeholder="请输入你的答案" @@ -70,7 +73,10 @@ class simpleAnswer extends Component{ exercise.answer_status == 1 || questionType.a_flag ?

    参考答案:

    -
  • + {/*
  • */} +

    this.showAndHide(false)}>隐藏参考答案

    : @@ -82,7 +88,10 @@ class simpleAnswer extends Component{ isStudent && exercise.answer_open==true && exercise.exercise_status == 3 ?

    参考答案:

    -
  • + {/*
  • */} +
    :"" }
    diff --git a/public/react/src/modules/courses/exercise/question/single.js b/public/react/src/modules/courses/exercise/question/single.js index 4ff4bf12b..510c28b48 100644 --- a/public/react/src/modules/courses/exercise/question/single.js +++ b/public/react/src/modules/courses/exercise/question/single.js @@ -1,7 +1,7 @@ import React,{ Component } from "react"; import {Checkbox,Radio, Input} from "antd"; -import {markdownToHTML} from 'educoder' +import {markdownToHTML, MarkdownToHtml} from 'educoder' import axios from 'axios' const tagArray = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', @@ -46,7 +46,10 @@ class single extends Component{

    {prefix} {/* */} - + {/* */} +

    ) }) diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseReply.js b/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseReply.js index 1e0fb3071..6c7085ca2 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseReply.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTasksappraiseReply.js @@ -190,7 +190,7 @@ export default ImageLayerOfCommentHOC() (GraduationTasksappraiseReply); {/*className="edu-tab-con-box clearfix edu-txt-center">*/} {/**/} - {/*

    没有数据可以显示!

    */} + {/*

    暂时还没有相关数据哦!

    */} {/*
    */} {/*
    */} {/*
    */} \ No newline at end of file diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssetting.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssetting.js index 5bbbe1a14..d6382165b 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssetting.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssetting.js @@ -896,7 +896,7 @@ class GraduationTaskssettingapp extends Component{ } /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true' ).then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js index d773d8411..1b98f00f3 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettinglist.js @@ -645,7 +645,7 @@ class GraduationTaskssettinglist extends Component{ b_order:b_order, search:search, } - axios.get(url,{ + axios.get(url + '?export=true',{ params }).then((response) => { if(response === undefined){ @@ -1307,7 +1307,7 @@ class GraduationTaskssettinglist extends Component{
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    @@ -1573,7 +1573,7 @@ class GraduationTaskssettinglist extends Component{ className="edu-tab-con-box clearfix edu-txt-center"> -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js index 1bf6eb962..a812bd803 100644 --- a/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js +++ b/public/react/src/modules/courses/graduation/tasks/GraduationTaskssettingquestions.js @@ -199,7 +199,7 @@ class GraduationTasksquestions extends Component{ /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true').then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/courses/graduation/topics/index.js b/public/react/src/modules/courses/graduation/topics/index.js index f4303ff87..84b500716 100644 --- a/public/react/src/modules/courses/graduation/topics/index.js +++ b/public/react/src/modules/courses/graduation/topics/index.js @@ -322,7 +322,7 @@ onBoardsNew=()=>{ } /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true').then((response) => { if(response.data.status&&response.data.status===-1){ }else if(response.data.status&&response.data.status===-2){ diff --git a/public/react/src/modules/courses/members/studentsList.js b/public/react/src/modules/courses/members/studentsList.js index 363d06c54..d7c4cb85b 100644 --- a/public/react/src/modules/courses/members/studentsList.js +++ b/public/react/src/modules/courses/members/studentsList.js @@ -36,8 +36,10 @@ const buildColumns = (that) => { key: 'login', align:'center', className:"color-grey-6", - render: (name, record) => { - return {name} + render: (login, record) => { + return 10 ? login : ''} + >{login} } }, { title: '姓名', @@ -57,8 +59,8 @@ const buildColumns = (that) => { align:'center', className:"color-grey-6", render: (student_id, record) => { - return {student_id} + return 10 ? student_id : ''} + style={{maxWidth: '160px'}} >{student_id} } }]; if (course_groups && course_groups.length) { @@ -125,7 +127,7 @@ class studentsList extends Component{ } /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '&export=true').then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/courses/poll/PollDetailIndex.js b/public/react/src/modules/courses/poll/PollDetailIndex.js index b1e8c3443..cdc6a5ae2 100644 --- a/public/react/src/modules/courses/poll/PollDetailIndex.js +++ b/public/react/src/modules/courses/poll/PollDetailIndex.js @@ -75,7 +75,7 @@ class PollDetailIndex extends Component{ /// 确认是否下载 confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true' ).then((response) => { if(response.data.status&&response.data.status===-1){ }else if(response.data.status&&response.data.status===-2){ diff --git a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js index 8ec2ffcbc..17778dea9 100644 --- a/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js +++ b/public/react/src/modules/courses/shixunHomework/Listofworksstudentone.js @@ -2214,7 +2214,7 @@ class Listofworksstudentone extends Component { confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '&export=true').then((response) => { if(response === undefined){ return } @@ -2528,7 +2528,7 @@ class Listofworksstudentone extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    @@ -2747,7 +2747,7 @@ class Listofworksstudentone extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    @@ -2945,7 +2945,7 @@ class Listofworksstudentone extends Component {
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/react/src/modules/courses/shixunHomework/ShixunStudentWork.js b/public/react/src/modules/courses/shixunHomework/ShixunStudentWork.js index 4bb44b697..97bc651ea 100644 --- a/public/react/src/modules/courses/shixunHomework/ShixunStudentWork.js +++ b/public/react/src/modules/courses/shixunHomework/ShixunStudentWork.js @@ -539,7 +539,7 @@ class ShixunStudentWork extends Component { } confirmysl(url){ - axios.get(url).then((response) => { + axios.get(url + '?export=true').then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunWorkModal.js b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunWorkModal.js index f1d1c43f3..cc9586577 100644 --- a/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunWorkModal.js +++ b/public/react/src/modules/courses/shixunHomework/Shixunworkdetails/ShixunWorkModal.js @@ -258,7 +258,7 @@ class ShixunWorkModal extends Component{
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js index b07392153..99c295c40 100644 --- a/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js +++ b/public/react/src/modules/courses/shixunHomework/Trainingjobsetting.js @@ -1766,16 +1766,16 @@ class Trainingjobsetting extends Component { daochushixunbaogao=()=>{ let url =`/zip/shixun_report?homework_common_id=${this.props.match.params.homeworkid}`; - this.confirmysl(url); + this.confirmysl(url, url + '&export=true'); } daochuzuoye =() =>{ let url = `/homework_commons/${this.props.match.params.homeworkid}/works_list.xlsx`; - this.confirmysl(url); + this.confirmysl(url, url + '?export=true'); } - confirmysl(url){ - axios.get(url).then((response) => { + confirmysl(url, urlWithExport){ + axios.get(urlWithExport).then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/courses/shixunHomework/Workquestionandanswer.js b/public/react/src/modules/courses/shixunHomework/Workquestionandanswer.js index a46d783ea..4ed45790d 100644 --- a/public/react/src/modules/courses/shixunHomework/Workquestionandanswer.js +++ b/public/react/src/modules/courses/shixunHomework/Workquestionandanswer.js @@ -339,16 +339,16 @@ class Workquestionandanswer extends Component { daochushixunbaogao=()=>{ let url =`/zip/shixun_report?homework_common_id=${this.props.match.params.homeworkid}`; - this.confirmysl(url); + this.confirmysl(url, url + '&export=true'); } daochuzuoye =() =>{ let url = `/homework_commons/${this.props.match.params.homeworkid}/works_list.xlsx`; - this.confirmysl(url); + this.confirmysl(url, url + '?export=true'); } - confirmysl(url){ - axios.get(url).then((response) => { + confirmysl(url, urlWithExport){ + axios.get(urlWithExport).then((response) => { if(response === undefined){ return } diff --git a/public/react/src/modules/forums/MemoList.js b/public/react/src/modules/forums/MemoList.js index fae728542..26cad1448 100644 --- a/public/react/src/modules/forums/MemoList.js +++ b/public/react/src/modules/forums/MemoList.js @@ -31,7 +31,7 @@ class MemoList extends Component { {!memo_list || memo_list.length === 0 ?
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    : renderMemoList() } diff --git a/public/react/src/modules/home/shixunsHome.js b/public/react/src/modules/home/shixunsHome.js index 003724ede..65284d0f8 100644 --- a/public/react/src/modules/home/shixunsHome.js +++ b/public/react/src/modules/home/shixunsHome.js @@ -123,7 +123,7 @@ class ShixunsHome extends Component { {/*懒加载*/} - + {/**/}
    diff --git a/public/react/src/modules/login/LoginDialog.js b/public/react/src/modules/login/LoginDialog.js index 50038366d..58cd9b7fb 100644 --- a/public/react/src/modules/login/LoginDialog.js +++ b/public/react/src/modules/login/LoginDialog.js @@ -102,6 +102,8 @@ class LoginDialog extends Component { authCodeclass:'log-botton mt5', isRender: false, MyEduCoderModals:false, + Phonenumberisnotco:undefined, + Phonenumberisnotcobool:false, }; } @@ -112,26 +114,103 @@ class LoginDialog extends Component { register=(num) =>{ this.setState({login:1,speedy:num,dialogBox:'dialogBox2'}); } - - loginChange = () =>{ - let reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/; - let reg1 = /^1\d{10}$/; - let reg2=/^[a-zA-z]\w{3,14}$/; - // let reg3=/^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; - let value=this.refs.loginPassText.value; - let valuenum= value.length; - if(valuenum>0){ - if(!reg.test(value)&&!reg1.test(value)&&!reg2.test(value)){ - this.setState({regular:1}) - return - }else{ - this.setState({loginValue:value}) - this.setState({regular:0}) + inputOnBlur = (e, id) => { + this.Emailphonenumberverification(e.target.value, 1); + }; + // 输入页面 + loginChange = (e) =>{ + var stirngt=""; + if(e.target.value.length>0){ + var str= e.target.value.replace(/\s*/g,"") + stirngt=str; + }else{ + stirngt= e.target.value; + } + + if (e.target.value.length === 0) { + this.setState({ + loginValue: stirngt, + Phonenumberisnotco:undefined, + }) + }else{ + this.setState({ + loginValue: stirngt, + Phonenumberisnotco:undefined, + }) + } + // let reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/; + // let reg1 = /^1\d{10}$/; + // let reg2=/^[a-zA-z]\w{3,14}$/; + // // let reg3=/^[a-zA-Z0-9]+([.\-_\\]*[a-zA-Z0-9])*@([a-z0-9]+[-a-z0-9]*[a-z0-9]+.){1,63}[a-z0-9]+$/; + // let value=this.refs.loginPassText.value; + // let valuenum= value.length; + // if(valuenum>0){ + // if(!reg.test(value)&&!reg1.test(value)&&!reg2.test(value)){ + // this.setState({regular:1}) + // return + // }else{ + // // this.setState({loginValue:value}); + // this.setState({regular:0}); + // var stirngt; + // if(value.length>0){ + // var str= value.replace(/\s*/g,"") + // stirngt=str; + // }else{ + // stirngt= value; + // } + // this.setState({ + // loginValue:stirngt, + // }); + // } + // }else{ + // this.setState({loginValue:value}); + // var stirngt; + // if(value.length>0){ + // var str= value.replace(/\s*/g,"") + // stirngt=str; + // }else{ + // stirngt= value; + // } + // this.setState({ + // loginValue:stirngt, + // }); + // } + }; + //邮箱手机号验证 + Emailphonenumberverification = (value, id) => { + var url = `/accounts/valid_email_and_phone.json`; + axios.get((url), { + params: { + login: value, + type: 1, + } + }).then((result) => { + if(result){ + if(result.data.status===-2){ + if(result.data.message==="该手机号码或邮箱已被注册"){ + this.setState({ + Phonenumberisnotco: undefined, + Phonenumberisnotcobool: false, + }) + }else { + this.setState({ + Phonenumberisnotco: result.data.message, + Phonenumberisnotcobool: true, + }) + } + return; + }else { + this.setState({ + Phonenumberisnotco: undefined, + Phonenumberisnotcobool: false, + }) + return; } - }else{ - this.setState({loginValue:value}) } - } + }).catch((error) => { + + }) + }; passwordChange = () =>{ let value =this.refs.passwordText.value; @@ -360,7 +439,7 @@ class LoginDialog extends Component { if(response.status===200){ if (response.data.status === 402) { - window.location.href = response.data.url; + // window.location.href = response.data.url; }else if (response.data.status === -2) { notification.open({ message: '提示', @@ -411,7 +490,7 @@ class LoginDialog extends Component { window.location.href = url; }; render() { - let{open,login,speedy,loginValue,regular,isGoing,isGoingValue,disabled,bottonclass, + let{open,login,speedy,loginValue,regular,isGoing,isGoingValue,disabled,bottonclass,Phonenumberisnotco, dialogBox,shortcutnum,disabledType,gaincode,authCodeType,authCodeclass, isRender}=this.state; if (isRender === undefined) { @@ -457,11 +536,13 @@ class LoginDialog extends Component { id="name_loggin_input" ref="loginPassText" onInput={this.loginChange} + onBlur={(e) => this.inputOnBlur(e, 1)} + value={this.state.loginValue} name="username" placeholder="请输入有效的手机号/邮箱号" >

    请输入有效的手机号/邮箱号

    + style={{display: Phonenumberisnotco===undefined?'none':'block'}}>{Phonenumberisnotco}

    { this.modalCancel(); - window.open(`/users/${this.props.user.login}/private_messages`) + window.open(`/users/${this.props.user.login}/message_detail?user_id=1`) } modalCancel = () => { this.setState({ diff --git a/public/react/src/modules/modals/DownloadMessageysl.js b/public/react/src/modules/modals/DownloadMessageysl.js index 3f81a93a6..b5c23960a 100644 --- a/public/react/src/modules/modals/DownloadMessageysl.js +++ b/public/react/src/modules/modals/DownloadMessageysl.js @@ -11,7 +11,7 @@ class DownloadMessageysl extends Component { setDownload=()=>{ this.props.modalCancel(); - window.open(`/users/${this.props.user.login}/private_messages`) + window.open(`/users/${this.props.user.login}/message_detail?user_id=1`) } render() { diff --git a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js index 2d7bcc0e0..6f771ece8 100644 --- a/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js +++ b/public/react/src/modules/paths/PathDetail/DetailCardsEditAndAdd.js @@ -500,7 +500,9 @@ class DetailCardsEditAndAdd extends Component{
  • 恢复 ? / 不恢复'; + $("#e_tips_"+id).html(h); + } + setInterval(function() { + var d = new Date(); + var h = d.getHours(); + var m = d.getMinutes(); + var s = d.getSeconds(); + h = h < 10 ? '0' + h : h; + m = m < 10 ? '0' + m : m; + s = s < 10 ? '0' + s : s; + if(editor.getValue().trim() != ""){ + md_add_data("content",mdu,editor.getValue()); + var id1 = "#e_tip_"+id; + var id2 = "#e_tips_"+id; + + var textStart = " 数据已于 " + var text = textStart + h + ':' + m + ':' + s +" 保存 "; + // 占位符 + var oldHtml = $(id2).html(); + if (oldHtml && oldHtml != ' ' && oldHtml.startsWith(textStart) == false) { + $(id2).html( oldHtml.split(' (')[0] + ` (${text})`); + } else { + $(id2).html(text); + } + // $(id2).html(""); + } + },10000); + + }else{ + $("#e_tip_"+id).after('您的浏览器不支持localStorage.无法开启自动保存草稿服务,请升级浏览器!'); + } +} + + +function create_editorMD(id, width, high, placeholder, imageUrl, callback, initValue, + onchange, watch, { noStorage, showNullButton }, that) { + // 还是出现了setting只有一份,被共用的问题 + + var editorName = window.editormd(id, { + width: width, + height: high===undefined?400:high, + path: path, // "/editormd/lib/" + markdown : initValue, + + dialogLockScreen: false, + watch:watch===undefined?true:watch, + syncScrolling: "single", + tex: true, + tocm: true, + emoji: true, + taskList: true, + codeFold: true, + searchReplace: true, + htmlDecode: "style,script,iframe", + sequenceDiagram: true, + autoFocus: false, + + // mine + + toolbarIcons: function (mdEditor) { + // + // let react_id = `react_${id}`; + // const __that = window[react_id] + + // Or return editormd.toolbarModes[name]; // full, simple, mini + // Using "||" set icons align right. + const icons = ["bold", "italic", "|", "list-ul", "list-ol", "|", "code", "code-block", "|", "testIcon", "testIcon1", '|', "image", "table", '|', "watch", "clear"]; + // if (__that.props.showNullButton) { + // icons.push('nullBtton') + // } + return icons + + + }, + toolbarCustomIcons: { + testIcon: "
    ", + testIcon1: "
    ", + nullBtton: "
    点击插入填空项
    ", + }, + //这个配置在simple.html中并没有,但是为了能够提交表单,使用这个配置可以让构造出来的HTML代码直接在第二个隐藏的textarea域中,方便post提交表单。 + saveHTMLToTextarea: true, + // 用于增加自定义工具栏的功能,可以直接插入HTML标签,不使用默认的元素创建图标 + dialogMaskOpacity: 0.6, + placeholder: placeholder, + imageUpload: true, + imageFormats: ["jpg", "jpeg", "gif", "png", "bmp", "webp", "JPG", "JPEG", "GIF", "PNG", "BMP", "WEBP"], + imageUploadURL: imageUrl,//url + onchange: onchange, + onload: function() { + let _id = this.id // 如果要使用this,这里不能使用箭头函数 + let _editorName = this; + let react_id = `react_${_editorName.id}`; + const __that = window[react_id] + + // this.previewing(); + // let _id = id; + $("#" + _id + " [type=\"latex\"]").bind("click", function () { + _editorName.cm.replaceSelection("```latex"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("\n"); + _editorName.cm.replaceSelection("```"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + + $("#" + _id + " [type=\"inline\"]").bind("click", function () { + _editorName.cm.replaceSelection("$$$$"); + var __Cursor = _editorName.cm.getDoc().getCursor(); + _editorName.cm.setCursor(__Cursor.line, __Cursor.ch - 2); + _editorName.cm.focus(); + }); + $("[type=\"inline\"]").attr("title", "行内公式"); + $("[type=\"latex\"]").attr("title", "多行公式"); + + if (__that.props.showNullButton) { + const NULL_CH = '▁' + // const NULL_CH = '〇' + // const NULL_CH = '🈳' + + $("#" + _id + " [type=\"nullBtton\"]").bind("click", function () { + _editorName.cm.replaceSelection(NULL_CH); + // var __Cursor = _editorName.cm.getDoc().getCursor(); + // _editorName.cm.setCursor(__Cursor.line - 1, 0); + }); + } + + if (noStorage == true) { + + } else { + md_elocalStorage(_editorName, `MDEditor__${_id}`, _id); + } + + callback && callback(_editorName) + } + }); + return editorName; +} + + +export default class MDEditors extends Component { + constructor(props) { + super(props) + this.state = { + initValue: '' + } + } + componentDidUpdate(prevProps, prevState) { + // 不能加,影响了试卷填空题 + // if (this.props.initValue != prevProps.initValue) { + // this.answers_editormd.setValue(this.props.initValue) + // } + } + + // react_mdEditor_ + componentDidMount = () => { + const { mdID, initValue, placeholder, showNullButton} = this.props; + + let _id = `mdEditor_${mdID}` + this.contentChanged = false; + const _placeholder = placeholder || ""; + // amp; + // 编辑时要传memoId + const imageUrl = `/upload_with_markdown?container_id=&container_type=Memo`; + // 创建editorMd + let react_id = `react_${_id}`; + + window[react_id] = this + const answers_editormd = create_editorMD(_id, '100%', this.props.height, _placeholder, imageUrl, (__editorName) => { + react_id = `react_${__editorName.id}`; + const that = window[react_id] + + setTimeout(() => { + console.log('timeout', __editorName.id) + __editorName.resize() + __editorName.cm && __editorName.cm.refresh() + }, that.props.refreshTimeout || 500) + if (that.props.initValue != undefined && that.props.initValue != '') { + __editorName.setValue(that.props.initValue) + } + if (that.state.initValue) { + __editorName.setValue(that.state.initValue) + } + __editorName.cm.on("change", (_cm, changeObj) => { + that.contentChanged = true; + if (that.state.showError) { + that.setState({showError: false}) + } + that.onEditorChange() + }) + that.props.onCMBlur && __editorName.cm.on('blur', () => { + that.props.onCMBlur() + }) + that.props.onCMBeforeChange && __editorName.cm.on('beforeChange', (cm,change) => { + that.props.onCMBeforeChange(cm,change) + }) + that.answers_editormd = __editorName; + window[_id] = __editorName; + }, initValue, this.onEditorChange,this.props.watch, { + noStorage: this.props.noStorage, + showNullButton: this.props.showNullButton + }, this); + + } + showError = () => { + this.setState({showError: true}) + } + onEditorChange = () => { + this.props.setcheckoutcontent() + if (!this.answers_editormd) return; + const val = this.answers_editormd.getValue(); + try { + this.props.onChange && this.props.onChange(val) + } catch(e) { + // http://localhost:3007/courses/1309/common_homeworks/6566/setting + // 从这个页面,跳转到编辑页面,再在编辑页面点击返回的时候,这里会报错 + console.error('出错') + console.error(e) + } + } + resize = () => { + if (!this.answers_editormd) { // 还未初始化 + return; + } + this.answers_editormd.resize() + this.answers_editormd.cm && this.answers_editormd.cm.refresh() + this.answers_editormd.cm.focus() + } + + getValue = () => { + try { + return this.answers_editormd.getValue() + } catch (e) { + return '' + } + } + setValue = (val) => { + try { + this.answers_editormd.setValue(val) + } catch (e) { + // TODO 这里多实例的时候,前一个实例的state会被后面这个覆盖 参考NewWork.js http://localhost:3007/courses/1309/homework/9300/edit/1 + // 未初始化 + this.setState({ initValue: val }) + } + } + + render() { + + let { + showError + } = this.state; + let { mdID, className, noStorage } = this.props; + let _style = {} + if (showError) { + _style.border = '1px solid red' + } + return ( + +
    + {/* padding10-20 */} +
    + +
    +
    +
    +
    +
    + {noStorage == true ? ' ' :

     

    } + {/* {noStorage == true ? ' ' :

     

    } */} +
    +
    + ) + } +} + + diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js b/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js new file mode 100644 index 000000000..bc5aee524 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageBanner.js @@ -0,0 +1,25 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; + +class PackageBanner extends Component { + constructor(props) { + super(props) + this.state = { + + } + } + componentDidMount() { + + + } + + + render() { + return ( +
    + ) + } +} + +export default PackageBanner; + diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js b/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js new file mode 100644 index 000000000..cfc54bb98 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageConcent.js @@ -0,0 +1,299 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import axios from 'axios'; +import { Input ,Icon,Button,Pagination} from 'antd'; +import moment from 'moment'; +import '../packageconcnet.css'; + +const { Search } = Input; +let categorylist=[ + {name:"全部",value:undefined}, + {name:"前端开发",value:"front"}, + {name:"后端开发",value:"backend"}, + {name:"移动开发",value:"mobile"}, + {name:"数据库",value:"database"}, + {name:"云计算和大数据",value:"cloud_compute_and_big_data"}, + {name:"人工智能",value:"ai"}, + {name:"运维与测试",value:"devops_and_test"}, + {name:"其他",value:"other"}, +] +// +function setcategorylist(val){ + let vals="" + categorylist.some((item,key)=> { + if (item.name === val) { + vals=item.value + return true + } + } + ) + + return vals +} + + + +class PackageConcent extends Component { + constructor(props) { + super(props) + this.state = { + data:undefined, + project_packages:undefined, + category:undefined, + keyword:undefined, + sort_by:"recently", + sort_direction:"desc", + page:1, + per_page:20, + categories:[] + } + } + //desc’, ‘desc’, ‘asc’ + //否 string 排序,默认最新, ‘recently’, ‘price’ + // 否 string 类型, front,backend,mobile,database, cloud_compute_and_big_data,devops_and_test,ai,other + componentDidMount() { + window.document.title = '众包创新' + let {category,keyword,sort_by,sort_direction,page}=this.state + this.setdatas(category,keyword,sort_by,sort_direction,page) + + let Url = `/project_package_categories.json`; + axios.get(Url).then((response) => { + // console.log(response) + this.setState({ + categories:response.data.categories + }) + }).catch((error) => { + console.log(error) + }) + + } + + setdatas=(category,keyword,sort_by,sort_direction,page)=>{ + + let Url = `/project_packages.json`; + axios.get(Url,{params:{ + category_id:category, + keyword:keyword, + sort_by:sort_by, + sort_direction:sort_direction, + page:page, + per_page:20, + }} + ).then((response) => { + this.setState({ + data:response.data, + project_packages:response.data.project_packages + }) + }).catch((error) => { + console.log(error) + }) + } + + setdatafuns=(value)=>{ + let {category,keyword,sort_by,sort_direction,page}=this.state + this.setState({ + keyword:value + }) + this.setdatas(category,value,sort_by,sort_direction,page) + } + + + setcategory=(value)=>{ + let {category,keyword,sort_by,sort_direction,page}=this.state + this.setState({ + category:value + }) + this.setdatas(value,keyword,sort_by,sort_direction,page) + } + + setsort_byfun=(value)=>{ + let {category,keyword,sort_by,sort_direction,page}=this.state + + this.setState({ + sort_by:value + }) + let sort_directionvalue; + if(value===sort_by){ + if(sort_direction==="desc"){ + this.setState({ + sort_direction:"asc" + }) + sort_directionvalue="asc"; + }else{ + this.setState({ + sort_direction:"desc" + }) + sort_directionvalue="desc"; + } + }else{ + this.setState({ + sort_direction:"desc" + }) + sort_directionvalue="desc"; + } + + this.setdatas(category,keyword,value,sort_directionvalue,page) + } + render() { + let {data,page,category,sort_by,sort_direction,project_packages}=this.state; + + return ( +
    + +
    +
    +
    +
    +
    + + + {/*concent*/} +
    +
    +

    +

    + 搜索} + onSearch={ (value)=>this.setdatafuns(value)} /> + +

    +

    +
    +
    + +
    +

    +

    + 类型: +

    +
  • this.setcategory(undefined)}>全部
  • + {this.state.categories.map((item,key)=>{ + return( +
  • this.setcategory(item.id)}>{item.name}
  • + ) + })} + +
    +

    + +

    + 排序: +

    +
  • this.setsort_byfun("recently")}> + 最新 + + + + +
  • + +
  • this.setsort_byfun("price")}> + 价格 + + + + +
  • +
    +

    +

    +
    + + + {project_packages&&project_packages.map((item,key)=>{ + return( +
    + +
    + +
    + +
    + +
    + +
    + + + +
    + +
    + {item.min_price===null?"":¥{item.min_price}} + {item.max_price===null||item.min_price===null?"":~} + {item.max_price===null?"":¥{item.max_price}} + {item.min_price===null&&item.max_price===null?可议价:""} +
    + +
    + +
    +
    {item.category_name}
    +
    + +
    +
    + + {item.visit_count}人浏览 +
    +
    + + + {moment(item.deadline_at).endOf('day').fromNow()}竞标截止 + +
    +
    + + + {item.bidding_users_count}人竞标 + +
    +
    +
    + {item.published_at===null?更新于:{moment(item.updated_at).format("YYYY-MM-DD HH:mm")} : + 发布于:{moment(item.published_at).format("YYYY-MM-DD HH:mm")} } +
    +
    + +
    + +
    +
    + ) + })} + {project_packages&&project_packages.length===0?
    +
    + +

    暂无数据哦~

    +
    :""} + +
    + +
    + + +
    +
    + + + + + ) + } +} + +export default PackageConcent; + diff --git a/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js b/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js new file mode 100644 index 000000000..e6c7cdc98 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndex/PackageIndex.js @@ -0,0 +1,30 @@ +import React, { Component } from 'react'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; + +//业务组件 +import PackageBanner from "./PackageBanner"; +import PackageConcent from "./PackageConcent"; + +class PackageIndex extends Component{ + constructor(props) { + super(props) + } + + componentDidMount(){ + window.document.title = '众包创新' + } + + render() { + return ( +
    +
    + {/*头部banner*/} + + {/*内容banner*/} + +
    +
    + ) + } +} +export default PackageIndex; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/NEITaskDetailsModel.js b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/NEITaskDetailsModel.js new file mode 100644 index 000000000..16e22dae0 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/NEITaskDetailsModel.js @@ -0,0 +1,41 @@ +import React, { Component } from 'react'; +import { Spin, Icon , Modal,Input,Button} from 'antd'; +class NEITaskDetailsModel extends Component { + + constructor(props) { + super(props); + this.state = { + + } + } + + render() { + + return( + +
    +

    +

    {this.props.applyvalue}
    +
    {this.props.applybottom}
    +

    +
    + 取消 + 确定 +
    + +
    +
    + ) + } +} + +export default NEITaskDetailsModel; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/PackageIndexNEITaskDetails.js b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/PackageIndexNEITaskDetails.js new file mode 100644 index 000000000..ac7c8a1a5 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/PackageIndexNEITaskDetails.js @@ -0,0 +1,487 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import axios from 'axios'; +import { Input ,Icon,Button,Pagination,DatePicker,Breadcrumb} from 'antd'; +import { handleDateString,markdownToHTML,bytesToSize,getImageUrl} from 'educoder'; +import NEITaskDetailsModel from './NEITaskDetailsModel'; +import moment from 'moment'; +import '../packageconcnet.css'; +import './pds.css' +import gouxuan from './img/gouxuan.png' +import weigouxuan from './img/weigouxuan.png' +const { Search } = Input; +// let categorylist=[ +// {name:"全部",value:undefined}, +// {name:"前端开发",value:"front"}, +// {name:"后端开发",value:"backend"}, +// {name:"移动开发",value:"mobile"}, +// {name:"数据库",value:"database"}, +// {name:"云计算和大数据",value:"cloud_compute_and_big_data"}, +// {name:"人工智能",value:"ai"}, +// {name:"其他",value:"other"}, +// ] +// +// function setcategorylist(val){ +// let vals="" +// categorylist.some((item,key)=> { +// if (item.value === val) { +// vals=item.name +// return true +// } +// } +// ) +// +// return vals +// } + +class PackageIndexNEITaskDetails extends Component { + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.state = { + data:undefined, + modalCancel: false, + overtype:false, + setbiddingmantype:false, + datalist:[] + } + } + + componentDidMount() { + this.getdatas() + window.document.title = '众包创新' + } + + getdatas=()=>{ + let url =`/project_packages/${this.props.match.params.id}.json`; + axios.get(url).then((response) => { + this.setState({ + data:response.data + }) + }).catch((error) => { + console.log(error); + + }) + } + + setbiddingman=()=>{ + this.setState({ + setbiddingmantype:true + }) + } + + notsetbiddingman=()=>{ + let {data} =this.state; + let gouxuans2=data.bidding_users + for (var i=0;i{ + this.setState({ + modalCancel:false + }) + } + + setbiddingusers=()=>{ + let{datalist}=this.state; + if(datalist.length>0){ + this.setState({ + applytype:true, + applyvalue:`选择的${datalist.length}个竞标者将被设定为“中标”`, + applybottom:"是否确认执行?", + applycancel:this.setApplycancel, + applyconfirm:this.setApplysumbit + }) + } + + } + + setApplysumbit=()=>{ + this.setState({ + applytype:false, + }) + let{datalist}=this.state; + let newlist=[]; + datalist.map((item,key)=>{ + newlist.push(item.id) + }) + + + let url=`/project_packages/${this.props.match.params.id}/bidding_users/win.json`; + axios.post(url,{ + user_ids:newlist + }).then((response) => { + if(response.data.status===0){ + this.props.showSnackbar("提交成功"); + this.setState({ + setbiddingmantype:false + }) + this.getdatas() + }else if(response.data.status===-1){ + this.props.showSnackbar(response.data.message); + } + }).catch((error) => { + console.log(error) + }) + + } + + + + Clickteacher2=(e)=>{ + let {data} =this.state; + let newlist=[] + let gouxuans2=data.bidding_users + for (var i=0;i{ + this.setState({ + overtype:true + }) + } + + setout=()=>{ + this.setState({ + overtype:false + }) + } + + deletePackages=()=>{ + this.setState({ + applytype:true, + applyvalue:"是否确认删除?", + applycancel:this.setApplycancel, + applyconfirm:this.setApplydelect + }) + } + + setApplydelect=()=>{ + this.setState({ + applytype:false, + }) + let url=`/project_packages/${this.props.match.params.id}.json`; + axios.delete(url ).then((response) => { + // const status = response.data.status + // console.log(response) + this.props.showSnackbar('删除成功'); + }).catch((error) => { + console.log(error) + }) + } + + setBiddingApply=()=>{ + this.setState({ + applytype:true, + applyvalue:"是否确认报名?", + applycancel:this.setApplycancel, + applyconfirm:this.setApplyconfirm + }) + } + + setApplycancel=()=>{ + this.setState({ + applytype:false, + }) + } + + setApplyconfirm=()=>{ + this.setState({ + applytype:false, + }) + let url=`/project_packages/${this.props.match.params.id}/bidding_users.json`; + axios.post(url).then((response) => { + if(response.data.status===0){ + this.props.showSnackbar("报名成功"); + this.getdatas() + }else if(response.data.status===-1){ + this.props.showSnackbar(response.data.message); + } + }).catch((error) => { + console.log(error) + }) + + } + goback = () => { + // window.history.go(-1) + window.location.href="/crowdsourcings"; + } + + render() { + let {overtype,data}=this.state; + // console.log(data&&data.creator.login) + console.log(data) + return ( + data===undefined?"":
    +
    + +
    + + '} className={"fl"}> + {/*{this.props.current_user.username}*/} + + 众包创新 + + {data&&data.title} + + + 返回 +
    + +

    + +

    +
    + +
    + {data&&data.status==="pending"?
    +
    + + 未申请 +
    :data&&data.status==="applying"?
    +
    + + 待发布 +
    :""} + +
    +
    +
    + + + +
    + {data&&data.creator.name} +
    + + {data&&data.creator.login===this.props.current_user&&this.props.current_user.login?"":
    + {overtype===false? 头像联系TA: + 头像联系TA} +
    } +
    + + +
    + +
    + +
    + +
    + {data&&data.title} + +
    + +
    + {data&&data.min_price===null?"":{data&&data.min_price}} + {data&&data.max_price===null||data&&data.min_price===null?"":~} + {data&&data.max_price===null?"":{data&&data.max_price}} + {data&&data.min_price===null&&data&&data.max_price===null?可议价:""} +
    + +
    + +
    +
    {data&&data.category_name}
    +
    + +
    +
    + {data&&data.published_at===null? + 更新时间:{moment(data&&data.updated_at).format("YYYY-MM-DD HH:mm")} + : + 发布时间:{moment(data&&data.published_at).format("YYYY-MM-DD HH:mm")} + } +
    +
    + 竞标截止时间:{moment(data&&data.deadline_at).format("YYYY-MM-DD HH:mm")} +
    +
    + +
    + +
    +
    + +
    +
    + + {/*详情*/} +
    +
    +
    + 需求详情: + + {data&&data.status==="pending"&&data&&data.operation.can_select_bidding_user===true?
    + 编辑 + 删除 +
    :""} + +
    +
    +
    +
    + +
    + + {data&&data.attachments.length>0?
    +
    + 需求文件: +
    + {data&&data.attachments.map((item,key)=>{ + return( + + )})} +
    :""} +
    + + + + {/*发布者和竞选者状态show*/} + {this.state.setbiddingmantype===false&&data&&data.published_at!=null?
    + {/*下面是头像*/} +
    +
    +
    + 报名列表({data&&data.bidding_users.length}) +
    +
    + {data&&data.operation.can_bidding===true?:""} + {data&&data.operation.can_select_bidding_user===true?:""} +
    +
    +
    + +
    +
    +
    +
    + + {data&&data.bidding_users.map((item,key)=>{ + return( +
    + {item.status==="bidding_won"?:""} + +

    {item.name}

    + {this.props.current_user&&this.props.current_user.login!=item.login? + 头像联系TA + :""} +
    + ) + })} + + {data&&data.bidding_users.length===0?
    +
    + +

    暂无人员竞标~

    +
    :""} + + +
    +
    +
    +
    :""} + + + {this.state.setbiddingmantype===true?
    + {/*发布人选择状态*/} + {/*下面是头像*/} +
    +
    +
    + 报名列表({data&&data.bidding_users.length}) +
    + +
    +
    + 已选 ({this.state.datalist.length}) +
    + 取消 + +
    +
    +
    +
    +
    +
    +
    + {data&&data.bidding_users.map((item,key)=>{ + return( +
    + ) + })} + + {data&&data.bidding_users.length===0?
    +
    + +

    暂无人员竞标~

    +
    :""} + +
    +
    +
    +
    :""} + +

    + +
    + + +
    +
    +
    + ) + } +} + +export default PackageIndexNEITaskDetails; + + + diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/gouxuan.png b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/gouxuan.png new file mode 100644 index 000000000..5bc53f007 Binary files /dev/null and b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/gouxuan.png differ diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/weigouxuan.png b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/weigouxuan.png new file mode 100644 index 000000000..40ca55728 Binary files /dev/null and b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/img/weigouxuan.png differ diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newsone.png b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newsone.png new file mode 100755 index 000000000..9aadd57c2 Binary files /dev/null and b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newsone.png differ diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newstwo.png b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newstwo.png new file mode 100755 index 000000000..8ac58b2c4 Binary files /dev/null and b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/newstwo.png differ diff --git a/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/pds.css b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/pds.css new file mode 100644 index 000000000..504a78bed --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNEITaskDetails/pds.css @@ -0,0 +1,57 @@ +.ysldivhome2s{ + display: flex; + flex-flow: row wrap; + align-content:stretch; + flex-direction: row; + margin-bottom: 20px; +} + +.ysllogin_register_contentss{ + margin-top:0px !important; + padding-top: 10px; + padding-bottom: 10px; + display: flex; + margin-top: 20px; + /*justify-content: center;*/ + background: #fff; +} + +.ysldivhomediv1s{ + width: 80px; + height: 130px; + display: flex; + flex-direction:column; + margin-left: 48px; + margin-top: 20px; +} +.yslgouxuanimg{ + width: 20px; + height: 20px; + margin-left: 64px; + +} +.yslgouxuanimg2s{ + height: 20px; +} +.div1imgs{ + display: flex; + justify-content:center; + width: 80px; + height: 80px; + border-radius:50%; + +} +.textall{ + text-align: center; + font-size: 13px; + color: #4B4B4B; + +} +.ptext{ + width: 80px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; +} +.ysllogin_sections { + display: flex; + align-items: center; + flex-direction: column; +} \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js new file mode 100644 index 000000000..ffb28d3df --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBanner.js @@ -0,0 +1,41 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import { Steps, Divider } from 'antd'; +const { Step } = Steps; + +class PackageIndexNEIBanner extends Component { + constructor(props) { + super(props) + this.state = { + current:0 + } + } + componentDidMount() { + + + } + + onChange=(current)=>{ + debugger + console.log('onChange:', current); + this.setState({ current }); + }; + + render() { + const { current } = this.state; + return ( +
    +

    + + + + + +

    +
    + ) + } +} + +export default PackageIndexNEIBanner; + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js new file mode 100644 index 000000000..eae5589f2 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEIBannerConcent.js @@ -0,0 +1,940 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import axios from 'axios'; +import { Input , Spin, Icon ,Button,Pagination,DatePicker} from 'antd'; +import { handleDateString,getUrl,bytesToSize} from 'educoder'; +import locale from 'antd/lib/date-picker/locale/zh_CN'; +import MDEditors from '../MDEditors'; +import PhoneModel from './PhoneModel'; +import moment from 'moment'; +import '../packageconcnet.css'; +const { Search } = Input; +const $ = window.$; +let origin = getUrl(); + +// load +if (!window.postUpMsg) { + $.getScript( + `${origin}/javascripts/attachments.js`, + (data, textStatus, jqxhr) => { + + }); +} + + +function checkPhone(phone){ + + if(!(/^1[3456789]\d{9}$/.test(phone))){ + // alert("手机号码有误,请重填"); + return false; + } +} + +function range(start, end) { + const result = []; + for (let i = start; i < end; i++) { + result.push(i); + } + return result; +} + +function disabledDateTime() { + return { + disabledMinutes: () => range(1, 30).concat(range(31, 60)), + }; +} +class PackageIndexNEIBannerConcent extends Component { + constructor(props) { + super(props) + this.contentMdRef = React.createRef(); + this.state = { + modalCancel:false, + getverificationcodes:true, + seconds:35, + springtype:false, + category:undefined, + title:undefined, + content:undefined, + attachment_ids:undefined, + deadline_at:undefined, + min_price:undefined, + max_price:undefined, + contact_name:undefined, + contact_phone:undefined, + code:undefined, + publish:false, + categories:[] + } + } + + + componentDidMount() { + window.document.title = '众包创新' + if(this.props.match.params.id!=undefined){ + + let url=`/project_packages/${this.props.match.params.id}.json` + axios.get((url)).then((response) => { + console.log(response) + let data=response.data + this.setState({ + category:data.category_id, + title:data.title, + content:data.content, + deadline_at:moment(data.deadline_at), + min_price:data.min_price, + max_price:data.max_price, + contact_name:data.contact_name==null||data.contact_name==undefined?this.props.current_user.username:data.contact_name, + phones:data.contact_phone, + attachments:data.attachments, + + }) + }).catch((error) => { + console.log(error); + + }) + }else{ + console.log(this.props.current_user&&this.props.current_user.username) + } + + let Url = `/project_package_categories.json`; + axios.get(Url).then((response) => { + // console.log(response) + if(response.data.status===-1){ + + }else{ + this.setState({ + categories:response.data.categories + }) + } + + }).catch((error) => { + console.log(error) + }) + + this.setState({ + contact_name:this.props.current_user&&this.props.current_user.username + }) + + // this.contentMdRef.current.setValue("测试赋值") + } + + componentDidUpdate = (prevProps) => { + + if(prevProps.current_user!=this.props.current_user){ + if(this.props.current_user!=undefined){ + this.setState({ + contact_name:this.props.current_user.username + }) + } + } + + } + //获取验证码; + getverificationcode =()=>{ + // if (this.state.logins&&this.state.logins.length === 0) { + // // 判断没有输入手机号 + // return + // } + if(this.state.getverificationcodes === undefined){ + console.log("undefined"); + return; + } + if (this.state.getverificationcodes === true) { + this.setState({ + getverificationcodes: undefined, + }) + let timer = setInterval(() => { + this.setState((preState) => ({ + seconds: preState.seconds - 1, + }), () => { + if (this.state.seconds == 0) { + clearInterval(timer); + this.setState({ + getverificationcodes: false, + seconds: 35, + }) + } + }); + }, 1000) + //其他的网络请求也可以 + this.SMSverification(); + } else { + this.setState({ + getverificationcodes: undefined, + }) + let timer = setInterval(() => { + this.setState((preState) => ({ + seconds: preState.seconds - 1, + }), () => { + if (this.state.seconds == 0) { + clearInterval(timer); + this.setState({ + getverificationcodes: false, + seconds: 35, + + }) + } + }); + }, 1000) + //其他的网络请求也可以 + this.SMSverification(); + } + } + //短信验证 + SMSverification = () => { + let {contact_phone,code}=this.state; + var url = `/account/get_verification_code.json`; + axios.get((url), { + params: { + value: contact_phone, + type: 9, + } + }).then((result) => { + //验证有问题{"status":1,"message":"success"} + // console.log(result); + this.openNotification("验证码已发送,请注意查收!",2); + + + }).catch((error) => { + console.log(error); + + }) + } + + + onChangeTimePicker = (value, dateString) => { + if(value===null){ + this.setState({ + deadline_at:"" + }) + }else{ + if(moment(handleDateString(dateString))===undefined||moment(handleDateString(dateString))===null||moment(handleDateString(dateString))===""){ + this.setState({ + deadline_attypes:true + }) + }else{ + this.setState({ + deadline_attypes:false + }) + } + if(moment(handleDateString(dateString)){ + const content = this.contentMdRef.current.getValue().trim(); + if(content===undefined||content===null||content===""){ + this.setState({ + contenttypes:true + }) + }else{ + this.setState({ + contenttypes:false + }) + } + } + + + setcheckout=(min_price,max_price)=>{ + // if(min_price===undefined){ + // this.setState({ + // min_pricetype:true + // }) + // }else{ + // this.setState({ + // min_pricetype:false + // }) + // } + + + // if(parseInt(min_price)===undefined||parseInt(min_price)===null||parseInt(min_price)===""){ + // + // this.setState({ + // min_pricetype:true + // }) + // }else{ + // this.setState({ + // min_pricetype:false + // }) + // } + + // if(parseInt(max_price)===undefined||parseInt(max_price)===null||parseInt(max_price)===""){ + // + // this.setState({ + // min_pricetype:true + // }) + // + // }else{ + // this.setState({ + // min_pricetype:false + // }) + // } + + if(parseInt(min_price)<=0){ + this.setState({ + smallstype:true + }) + }else{ + this.setState({ + smallstype:false + }) + } + + if(parseInt(max_price){ + const content = this.contentMdRef.current.getValue().trim(); + // console.log(content) + // console.log(this.state.deadline_at._i) + this.setState({ + publish:type + }) + let types=type; + let {category,title,attachment_ids,deadline_at,min_price,max_price,contact_name,contact_phone,code,modalCancel}=this.state; + + if(category===undefined||category===null||category===""){ + this.setState({ + categorytypes:true + }) + this.scrollToAnchor("publishtimestart"); + return + } + + if(title===undefined||title===null||title===""){ + this.setState({ + titletypes:true + }) + this.scrollToAnchor("publishtimestart"); + return + } + + if(content===undefined||content===null||content===""){ + this.setState({ + contenttypes:true + }) + this.scrollToAnchor("publishtimestart"); + return + } + + if(deadline_at===undefined||deadline_at===null||deadline_at===""){ + this.setState({ + deadline_attypes:true + }) + this.scrollToAnchor("publishtime"); + return + } + + + if(moment(deadline_at) { + if(response.data.status===0){ + if(type===true){ + this.props.setPublicationfun(response.data.id) + }else{ + window.location.href="/crowdsourcings/"+response.data.id + } + this.setState({ + springtype:false + }) + }else if(response.data.status===-1){ + if(response.data.message==="无效的验证码"){ + this.setState({ + codeypesno:true, + springtype:false + }) + } + } + this.setState({ + springtype:false + }) + }).catch((error) => { + console.log(error) + this.setState({ + springtype:false + }) + }) + + + }else{ + + // edit + + const url = `/project_packages/${this.props.match.params.id}.json`; + + axios.put(url, { + category_id: category, + title: title, + content: content, + attachment_ids: attachment_ids, + deadline_at:deadline_at._i, + min_price:parseInt(min_price), + max_price:parseInt(max_price), + contact_name: contact_name===null||contact_name===undefined?this.props.current_user.username:contact_name, + contact_phone: contact_phone===undefined?this.props.current_user&&this.props.current_user.phone:contact_phone, + code:code, + publish:types + } + ).then((response) => { + if(response.data.status===0){ + if(type===true){ + this.props.setPublicationfun(response.data.id) + }else{ + window.location.href="/crowdsourcings/"+response.data.id + } + this.setState({ + springtype:false + }) + }else if(response.data.status===-1){ + if(response.data.message==="无效的验证码"){ + this.setState({ + codeypesno:true, + springtype:false + }) + } + } + this.setState({ + springtype:false + }) + }).catch((error) => { + console.log(error) + this.setState({ + springtype:false + }) + }) + + + } + + + + } + + modalCancel=()=>{ + this.setState({ + modalCancel:false, + contact_phone:undefined, + code:undefined, + }) + } + + editmodels=()=>{ + this.setState({ + modalCancel:true + }) + } + + + setcategory=(value)=>{ + if(value===undefined||value===null||value===""){ + this.setState({ + categorytypes:true + }) + }else{ + this.setState({ + categorytypes:false + }) + } + this.setState({ + category:value + }) + } + + settitlefun=(e)=>{ + + if(e.target.value===undefined||e.target.value===null||e.target.value===""){ + this.setState({ + titletypes:true + }) + }else{ + this.setState({ + titletypes:false + }) + } + + this.setState({ + title:e.target.value + }) + } + + + onChangemin_prices=(e)=>{ + let{max_price}=this.state; + this.setState({ + min_price:e.target.value + }) + this.setcheckout(e.target.value,max_price) + + + } + onChangemax_prices=(e)=>{ + let{min_price}=this.state; + this.setState({ + max_price:e.target.value + }) + this.setcheckout(min_price,e.target.value) + + } + + onChangeContact_name=(e)=>{ + + if(e.target.value===undefined||e.target.value===""||e.target.value===null){ + this.setState({ + contact_nametype:true + }) + }else{ + this.setState({ + contact_nametype:false + }) + } + + + this.setState({ + contact_name:e.target.value + }) + } + + onChangeContact_phone=(e)=>{ + let {modalCancel}=this.state; + // if(modalCancel===false){ + // if(this.props.current_user.phone===undefined||this.props.current_user.phone===null||this.props.current_user.phone===""){ + // this.setState({ + // current_userphonetype:true + // }) + // }else{ + // this.setState({ + // current_userphonetype:false + // }) + // } + // } + if(this.props.current_user&&this.props.current_user.phone===null||modalCancel===true){ + if(e.target.value===undefined||e.target.value===null||e.target.value===""){ + this.setState({ + contact_phonetype:true + }) + }else{ + this.setState({ + contact_phonetype:false + }) + } + + if(checkPhone(e.target.value)===false){ + this.setState({ + contact_phonetypes:true + }) + }else{ + this.setState({ + contact_phonetypes:false + }) + } + } + + + this.setState({ + contact_phone:e.target.value + }) + } + + onChangeCode=(e)=>{ + if(e.target.value===undefined||e.target.value===""||e.target.value===null){ + this.setState({ + codeypes:true + }) + }else{ + this.setState({ + codeypes:false + }) + } + this.setState({ + code:e.target.value + }) + } + + //跳转道描点的地方 + scrollToAnchor = (anchorName) => { + if (anchorName) { + // 找到锚点 + let anchorElement = document.getElementById(anchorName); + // 如果对应id的锚点存在,就跳转到锚点 + if(anchorElement) { anchorElement.scrollIntoView(); } + } + } + + render() { + let {modalCancel,seconds,getverificationcodes,attachments, + category,title}=this.state; + let categorylist=[ + {name:"前端开发",value:"front"}, + {name:"后端开发",value:"backend"}, + {name:"移动开发",value:"mobile"}, + {name:"数据库",value:"database"}, + {name:"云计算和大数据",value:"cloud_compute_and_big_data"}, + {name:"人工智能",value:"ai"}, + {name:"其他",value:"other"}, + ] + + + return ( + +
    + {/**/} + +

    + +

    +
    +
    + +
    + +

    +

    + {this.state.categories.map((item,key)=>{ + return( +
  • this.setcategory(item.id)}>{item.name}
  • + ) + })} +
    +

    + {this.state.categorytypes===true?
    请选择类型
    :""} + +
    + +
    + + + {this.state.titletypes===true?
    不能为空
    :""} + this.setcheckoutcontent()}> + {/* 请求status 422 */} + {this.state.contenttypes===true?
    不能为空
    :""} + {/*
    */} + {/* window.$('#_file').click()}*/} + {/*data-tip-down="请选择文件上传">*/} + {/*/!**!/*/} + {/*上传附件*/} + {/**/} + {/*(最多可添加 5 个图片/文件,每个大小不超过 10MB)*/} + {/*
    */} + {/*{attachments&&attachments.map((item,key)=>{*/} + {/*return(*/} + {/**/} + {/*)})}*/} + {/*
    */} + {/**/} + {/**/} + {/**/} + {/* {*/} + {/*debugger;*/} + {/*console.log(window.$('.file_selector')[0])*/} + {/*window.addInputFiles(window.$('.file_selector')[0])*/} + {/*}}*/} + {/*style={{'display': 'none'}}*/} + {/*type="file">*/} + {/**/} + {/**/} + {/*
    */} + + +
    +
    + +
    +
    +
    + +
    +

    + 竞标截止: + + + {this.state.deadline_attypes===true?

    不能为空
    :""} + + {this.state.deadline_attypexy===true?
    不能早于当前时间
    :""} +

    +

    + 支付费用: + this.onChangemin_prices(e)} + suffix={ + ¥ + } + /> + + this.onChangemax_prices(e)} + suffix={ + ¥ + } + />不填,则表示可议价 + {this.state.min_pricetype===true?

    不能为空
    :""} + {this.state.smallstype===true?
    不能小于零
    :""} + {this.state.minmaxtype===true?
    最高费用不能小于最低费用
    :""} +

    +
    + +
    +

    + 姓名: + this.onChangeContact_name(e)} + /> + {this.state.contact_nametype===true?

    不能为空
    :""} +

    + + {this.props.current_user&&this.props.current_user.phone!=null&&modalCancel===false?

    + 手机号: + + + this.editmodels()}> + +

    :""} + {/*{this.state.current_userphonetype===true?
    不能为空
    :""}*/} + {this.props.current_user&&this.props.current_user.phone===null||modalCancel===true?

    + + + {/*未注册才显示!*/} + + 手机号: + this.onChangeContact_phone(e)} + /> + {this.state.contact_phonetype===true?

    不能为空
    :""} + {this.state.contact_phonetypes===true?
    请输入正确的手机号
    :""} + + + + + 重新发送 ({seconds}s): getverificationcodes === true ?获取验证码 :重新发送} + onSearch={()=>this.getverificationcode()} + onInput={(e)=>this.onChangeCode(e)} + /> + {this.state.codeypes===true?
    验证码不能为空
    :""} + {this.state.codeypesno===true?
    验证码不正确
    :""} +
    + + {/**/} + + + + this.modalCancel()}>X + +

    :""} + + +
    +
    +

    + +
    + + this.setPublication(false)}>保存 +
    +
    +
    + + ) + } +} + +export default PackageIndexNEIBannerConcent; + +// attachments:[ +// { +// id: 206525, +// title: "412420b57ed8c141963d4c548bde551f", +// filesize: 18523, +// description: null, +// url: "/api/attachments/206525" +// } +// ] + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEISubmit.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEISubmit.js new file mode 100644 index 000000000..932b9295f --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNEISubmit.js @@ -0,0 +1,49 @@ +import React, {Component} from 'react'; +import {Link} from "react-router-dom"; +import { Icon ,Button} from 'antd'; + +class PackageIndexNEISubmit extends Component { + constructor(props) { + super(props) + this.state = { + current:0 + } + } + componentDidMount() { + window.document.title = '众包创新' + } + setageload=(sum)=>{ + if(sum===undefined){ + window.location.href="/crowdsourcings/new" + }else{ + // this.props.history.push("/project_packages/"+sum) + window.location.href="/crowdsourcings/"+sum + } + + } + render() { + + return ( + + ) + } +} + +export default PackageIndexNEISubmit; + diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js new file mode 100644 index 000000000..8d73a6e55 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PackageIndexNewandEditIndex.js @@ -0,0 +1,68 @@ +import React, { Component } from 'react'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; + +//业务组件 +import PackageIndexNEIBanner from "./PackageIndexNEIBanner"; + +import PackageIndexNEIBannerConcent from "./PackageIndexNEIBannerConcent" + +import PackageIndexNEISubmit from './PackageIndexNEISubmit' +import '../packageconcnet.css'; +class PackageIndexNewandEditIndex extends Component{ + constructor(props) { + super(props) + this.state = { + setPublication:false, + id:undefined + } + } + + componentDidMount(){ + window.document.title = '众包创新' + } + + setPublicationfun=(ids)=>{ + this.setState({ + setPublication:true, + id:ids + }) + } + + goback = () => { + // window.history.go(-1) + window.location.href="/crowdsourcings"; + } + + render() { + let {setPublication}=this.state; + return ( + + ) + } +} +export default PackageIndexNewandEditIndex; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PhoneModel.js b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PhoneModel.js new file mode 100644 index 000000000..99d63e7c2 --- /dev/null +++ b/public/react/src/modules/projectPackages/PackageIndexNewandEdit/PhoneModel.js @@ -0,0 +1,140 @@ +import React, { Component } from 'react'; +import { Spin, Icon , Modal,Input,Button} from 'antd'; +class PhoneModel extends Component { + //getverificationcodes 是否是重新发送或者是获取验证码 + //多少秒 + constructor(props) { + super(props); + this.state = { + funmodalsType:false, + istype:false, + getverificationcodes:true, + seconds:35, + } + } + //获取验证码 + getverificationcode =()=>{ + // if (this.state.logins&&this.state.logins.length === 0) { + // 判断没有输入手机号 + // return + // } + + if (this.state.getverificationcodes === true) { + this.setState({ + getverificationcodes: undefined, + }) + let timer = setInterval(() => { + this.setState((preState) => ({ + seconds: preState.seconds - 1, + }), () => { + if (this.state.seconds == 0) { + clearInterval(timer); + this.setState({ + getverificationcodes: false, + seconds: 35, + }) + } + }); + }, 1000) + //其他的网络请求也可以 + this.SMSverification(); + } else { + this.setState({ + getverificationcodes: undefined, + }) + let timer = setInterval(() => { + this.setState((preState) => ({ + seconds: preState.seconds - 1, + }), () => { + if (this.state.seconds == 0) { + clearInterval(timer); + this.setState({ + getverificationcodes: false, + seconds: 35, + + }) + } + }); + }, 1000) + //其他的网络请求也可以 + this.SMSverification(); + } + } + //短信验证 + SMSverification = () => { + // var url = `/accounts/get_verification_code.json`; + // axios.get((url), { + // params: { + // login: this.state.logins, + // type: 1, + // } + // }).then((result) => { + // //验证有问题{"status":1,"message":"success"} + // // console.log(result); + // this.openNotification("验证码已发送,请注意查收!",2); + // + // + // }).catch((error) => { + // console.log(error); + // + // }) + } + render() { + let{getverificationcodes,seconds} =this.state; + const antIcons = + return( + +
    +

    + 手机号码: + + +

    +

    + + + 验证码: + + + + + { + getverificationcodes === undefined ? + + : getverificationcodes === true ? + + : + + + } + {/**/} + + + +

    + +
    + 取消 + 确定 +
    + +
    +
    + ) + } +} + +export default PhoneModel; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/ProjectPackageIndex.js b/public/react/src/modules/projectPackages/ProjectPackageIndex.js new file mode 100644 index 000000000..6f2e32b8b --- /dev/null +++ b/public/react/src/modules/projectPackages/ProjectPackageIndex.js @@ -0,0 +1,76 @@ +import React, { Component } from 'react'; + +import { Redirect } from 'react-router'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import Loading from '../../Loading' + +import Loadable from 'react-loadable'; +import { TPMIndexHOC } from '../tpm/TPMIndexHOC' +import { SnackbarHOC } from 'educoder' + + +const PackageIndex = Loadable({ + loader: () => import('./PackageIndex/PackageIndex'), + loading: Loading, +}) + +const PackageIndexNewandEdit = Loadable({ + loader: () => import('./PackageIndexNewandEdit/PackageIndexNewandEditIndex'), + loading: Loading, +}) + +const PackageIndexNEITaskDetails = Loadable({ + loader: () => import('./PackageIndexNEITaskDetails/PackageIndexNEITaskDetails'), + loading: Loading, +}) + +class ProjectPackageIndex extends Component { + constructor(props) { + super(props) + } + + componentDidMount(){ + window.document.title = '众包创新' + } + + render() { + + return ( +
    + + + {/*众包首页*/} + + () + } + > + + () + } + > + + () + } + > + + () + } + > + + +
    + ); + } +} + +export default SnackbarHOC() (TPMIndexHOC (ProjectPackageIndex)) ; \ No newline at end of file diff --git a/public/react/src/modules/projectPackages/packageconcnet.css b/public/react/src/modules/projectPackages/packageconcnet.css new file mode 100644 index 000000000..7a8c11897 --- /dev/null +++ b/public/react/src/modules/projectPackages/packageconcnet.css @@ -0,0 +1,360 @@ +.width1240{ + width:1240px; +} +.packinput .ant-input{ + height: 50px; + width:749px; + border-color: #E1EDF8 !important; +} + +.packinput .ant-input-group-addon .ant-btn{ + width:140px !important; + font-size: 18px; + height: 50px; + background:rgba(76,172,255,1); +} + +.setissues{ + width:280px; + height:50px; + background:rgba(76,172,255,1); + border-radius:4px; + margin-left: 15px; +} + +.pagetype li{ + color:#8F8F8F !important; +} + +.maxwidth700{ + max-width: 700px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.mbf10{ + margin-bottom:-10px; +} + +.PackageIndexNEIBanner{ + width:1200px; + height:110px; + background:rgba(255,255,255,1); + box-shadow:0px 2px 6px 0px rgba(125,125,125,0.26); + border-radius:8px; +} + +.padding110{ + padding: 39px 110px 0px; + box-sizing: border-box; +} + +.borderccc{ + border: 1px solid #ccc; +} + +.input-100-40s{ + width: 100%; + padding: 5px; + box-sizing: border-box; +} + +.fafafas{ + background-color: #fafafa!important; + height: 40px; +} + +.fafafas:focus{ + background-color: #fff!important; +} + +.fafas .ant-input{ + background-color: #fafafa!important; + height: 40px; +} + +.fafas .ant-input:focus{ + background-color: #fff!important; +} +.fafas .ant-input-group-addon .ant-btn{ + width:140px !important; + font-size: 14px; + height: 40px; + background:rgba(76,172,255,1); +} + +.newFormbox .upload_filename{ + line-height: 32px; +} + +.newFormbox .attachment span{ + line-height: 23px; +} + +.newFormbox .attachment .remove-upload{ + line-height: 28px; +} + +.pd26a0{ + padding: 26px 26px 16px 26px; +} + +.newFormbox .attachment .icon-fujian{ + font-size: 14px !important; + line-height: 14px; + margin-top: 9px; +} + +.newFormbox{ + height:20px +} + +.ml24{ + margin-left:24px; +} + +.defalutCancelbtns{ + display: block; + border: 1px solid #4CACFF !important; + background-color: #fff; + color: #4CACFF !important; + width:130px; + height:40px; + text-align: center; + line-height: 40px; + border-radius: 4px; +} + +.defalutSubmitbtns{ + background-color: #4CACFF; + height:40px; +} + +.defalutSubmitbtnmodels{ + width:127px; + height:30px; + background-color: #4CACFF; +} + +.ant-steps-item-process .ant-steps-item-icon{ + background-color: #4CACFF !important; +} + +.ant-steps-item-process .ant-steps-item-icon{ + background-color: #4CACFF !important; +} + +.padding200{ + padding: 115px 200px 215px 200px; +} + +.fontcircle{ + font-size: 80px; + display: inherit; +} + +.sumbtongs{ + font-size: 24px; + display: inherit; + text-align: center; +} + +.terraces{ + font-size: 16px; + display: inherit; + text-align: center; + color:#999; +} +.padding251{ + padding: 0px 245px; +} + +.ant-modal-title{ + text-align: center; +} +.ml17{ + margin-left: 17px; +} + +.project-package-items{ + display: -webkit-flex; + display: flex; + flex-direction: row; + margin:0px !important; + padding: 20px; + background: white; + margin-bottom:0px !important; + box-shadow: none !important; +} + +.mtf7{ + margin-top:-7px; +} + +.publicpart.orangeGreen { + border-left: 80px solid #29BD8B; +} + +.publicwords{ + left: 3px; + top: 18px; +} + +.project-packages-list .project-package-items .item-image{ + width:100px !important; +} + +.height185{ + height: 185px; +} + +.ContacttheTA{ + width: 80px; + height: 26px; + font-size: 14px; + line-height: 26px; + display: block; + border: 1px solid #4CACFF !important; + background-color: #fff; + color: #4CACFF !important; + text-align: center; + border-radius: 4px; +} +.ContacttheTAs{ + width: 80px; + height: 26px; + font-size: 14px; + line-height: 24px; + /*display: block;*/ + border: 1px solid #fff !important; + background-color: #4CACFF; + color: #fff !important; + text-align: center; + border-radius: 4px; +} +.ml28{ + margin-left: 28px; +} + +.longboxs{ + font-size: 16px; + font-family: MicrosoftYaHei-Bold; + font-weight: bold; + color: rgba(5,16,26,1); + border-left: 4px solid rgba(76,172,255,1); + padding-left: 10px; + margin-bottom: 20px; +} + +.padding020{ + padding: 0px 20px 20px; +} + +.mtf3{ + margin-top:-3px; +} + +.task-btn-nebules{ + background: #fff!important; + color: #4CACFF!important; + border: 1px solid #4CACFF!important; + margin-left: 20px; + cursor: pointer; + display: inline-block; + padding: 0 12px; + letter-spacing: 1px; + text-align: center; + font-size: 14px; + height: 30px; + line-height: 30px; + border-radius: 2px; +} + +.packageabsolute{ + position: absolute; + right: -16px; + top: -7px; +} +.relativef{ + position: relative; +} + +.homehove:hover .ptext{ + color: #4CACFF!important; +} + +.homehove:hover .ContacttheTAs{ + display: block; +} + +.topsj{ + position: absolute; + top: -6px; +} +.bottomsj{ + position: absolute; + bottom: -6px; +} +.touchSelect .ant-spin-dot-spin{ + margin-top: 30% !important; +} + +.pagenoedits{ + margin-left: 20px; + color: #ccc; +} + +.pagemancenter{ + text-align: center; +} + +.ml0{ + margin-left: 0px; +} +.tabelcli{ + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 850px; + display: table-cell; +} + +.mtf10{ + margin-top:-10px; +} + +.padding26{ + padding: 26px; + box-sizing: border-box; +} + +.pd26{ + padding: 26px; +} +.pd30a0{ + padding: 30px 30px 16px 30px; +} + +.shaiContent li.shaiItem:hover span{ + color: #fff !important; +} + +.shaiContent li.shaiItem:hover i.iconfont{ + color: #4CACFF!important +} + +.ant-form-item-requireds::before { + display: inline-block; + margin-right: 4px; + color: #f5222d; + font-size: 14px; + font-family: SimSun,sans-serif; + line-height: 1; + content: '*'; +} + +*, *::before, *::after { + -webkit-box-sizing: border-box; + box-sizing: border-box; +} \ No newline at end of file diff --git a/public/react/src/modules/tpm/NewFooter.js b/public/react/src/modules/tpm/NewFooter.js index 7f8cd502c..a85b35ccf 100644 --- a/public/react/src/modules/tpm/NewFooter.js +++ b/public/react/src/modules/tpm/NewFooter.js @@ -16,7 +16,8 @@ class NewFooter extends Component { render() { return ( -
    +
    + {/*newContainers*/}
    {/*
    diff --git a/public/react/src/modules/tpm/NewHeader.js b/public/react/src/modules/tpm/NewHeader.js index d197bc9c4..b84982d86 100644 --- a/public/react/src/modules/tpm/NewHeader.js +++ b/public/react/src/modules/tpm/NewHeader.js @@ -649,10 +649,22 @@ submittojoinclass=(value)=>{ {...this.state} {...this.props} />:""} - + 高校智能化教学与实训平台 -
    + + +
    {/*<%= link_to image_tag("/images/educoder/logo.png", alt:"高校智能化教学与实训平台", className:"logoimg"), home_path %>*/}
    @@ -704,72 +716,77 @@ submittojoinclass=(value)=>{ />
  • 教学案例
  • -
  • 众包创新
  • +
  • 众包创新
  • 交流问答
  • 工程认证
  • - -
    -
    - {/**/} -
    - - 实训 - - -
    - {/**/} - {/*搜索框*/} - {showSearchOpentype===true?
    this.hideshowSearchOpen(e)} onMouseLeave={()=>this.setevaluatinghides()}> - this.onKeywordSearchKeyDowns()} - onSearch={(value) => this.onKeywordSearchKeyDown(value)} - // onPressEnter={this.onKeywordSearchKeyDown} - style={{ width: 300,height:32}} - autoFocus={true} - /> -
    :""} - - {/**/} - {/*/!**!/*/} - {/**/} - - {/**/} - {/* TODO 需要服务端接口提供最近搜索 + } + +
    +
    + {/**/} +
    + + 实训 + + +
    + {/**/} + {/*搜索框*/} + {showSearchOpentype===true?
    this.hideshowSearchOpen(e)} onMouseLeave={()=>this.setevaluatinghides()}> + this.onKeywordSearchKeyDowns()} + onSearch={(value) => this.onKeywordSearchKeyDown(value)} + // onPressEnter={this.onKeywordSearchKeyDown} + style={{ width: 300,height:32}} + autoFocus={true} + /> +
    :""} + + {/**/} + {/*/!**!/*/} + {/**/} + + {/**/} + {/* TODO 需要服务端接口提供最近搜索
    最近搜索
    */} -
    -
    - -
    +
    +
    {/* <%= link_to '登录', signin_path, :className => "mr5" %> @@ -777,16 +794,16 @@ submittojoinclass=(value)=>{ <%= link_to '注册', user_join_path, :className => "ml5" %> */} { user===undefined? - + this.educoderlogin()} className="mr5 color-white">登录 注册 - :user.login===""? + :user.login===""? this.educoderlogin()} className="mr5 color-white">登录 注册 : - ); diff --git a/public/react/src/modules/tpm/TPMIndex.css b/public/react/src/modules/tpm/TPMIndex.css index 1eb60bee8..2f6eccfd6 100644 --- a/public/react/src/modules/tpm/TPMIndex.css +++ b/public/react/src/modules/tpm/TPMIndex.css @@ -200,4 +200,12 @@ body>.-task-title { .HeaderSearch{ width: 325px; +} +.mainheighs{ + height: 100%; + display: block; +} + +.ml18a{ + margin-left:18%; } \ No newline at end of file diff --git a/public/react/src/modules/tpm/TPMIndexHOC.js b/public/react/src/modules/tpm/TPMIndexHOC.js index e092c17d4..b0bcf6f2a 100644 --- a/public/react/src/modules/tpm/TPMIndexHOC.js +++ b/public/react/src/modules/tpm/TPMIndexHOC.js @@ -20,7 +20,7 @@ const versionNum = '0001'; // let _url_origin = getUrl() let _url_origin=''; if(window.location.port === "3007"){ - _url_origin="https://newweb.educoder.net"; + _url_origin="http://47.96.87.25:48080"; } // let _url_origin=`https://www.educoder.net`; @@ -32,14 +32,14 @@ if (!window['indexHOCLoaded']) { // $('head').append($('') // .attr('href', `${_url_origin}/stylesheets/educoder/antd.min.css?1525440977`)); $('head').append($('') - .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?1525440977`)); + .attr('href', `${_url_origin}/stylesheets/css/edu-common.css?15254409771`)); $('head').append($('') - .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?1525440978`)); + .attr('href', `${_url_origin}/stylesheets/educoder/edu-main.css?15254409781`)); // index.html有加载 $('head').append($('') - .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?1525440978`)); + .attr('href', `${_url_origin}/stylesheets/educoder/edu-all.css?15254409781`)); // $('head').append($('') diff --git a/public/react/src/modules/user/LoginRegisterComponent.js b/public/react/src/modules/user/LoginRegisterComponent.js index eb0a3a5c2..48e1af926 100644 --- a/public/react/src/modules/user/LoginRegisterComponent.js +++ b/public/react/src/modules/user/LoginRegisterComponent.js @@ -14,12 +14,12 @@ import './common.css' import './commontwo.css' const { TabPane } = Tabs; const loginInputsyl = { -"width":"434px", -"height": "462px", -"-webkit-box-shadow": "3px 10px 21px 0px rgba(76,76,76,0.15)", -"box-shadow": "3px 10px 21px 0px rgba(76,76,76,0.15)", -"border-radius": "6px", -"background": "#fff" + "width":"434px", + "height": "462px", + "-webkit-box-shadow": "3px 10px 21px 0px rgba(76,76,76,0.15)", + "box-shadow": "3px 10px 21px 0px rgba(76,76,76,0.15)", + "border-radius": "6px", + "background": "#fff" } //父组件EducoderLogin.js @@ -66,6 +66,7 @@ class LoginRegisterComponent extends Component { pciphone:true, MyEduCoderModals:false, registered:undefined, + Phonenumberisnotcodmms:undefined, } } @@ -103,13 +104,14 @@ class LoginRegisterComponent extends Component { pciphone:true, MyEduCoderModals:false, registered:undefined, + Phonenumberisnotcodmms:undefined, } } } //判断是否是手机端 - IsPC=()=> { + IsPC=()=> { var userAgentInfo = navigator.userAgent; var Agents = ["Android", "iPhone", "SymbianOS", "Windows Phone", @@ -162,7 +164,7 @@ class LoginRegisterComponent extends Component { StudyMakeMoney = () => { // 调用父组件方法 - this.props.Setshowbool(3); + // this.props.Setlogins(3); this.setState({ login: "", @@ -170,7 +172,12 @@ class LoginRegisterComponent extends Component { logins: "", passwords: "", codes: "", - }) + }); + try { + this.props.Setshowbool(3); + }catch (e) { + + } } onTabChange = (activeKey) => { console.log("onTabChange"); @@ -294,6 +301,7 @@ class LoginRegisterComponent extends Component { //登入接口 postLogin = () => { + if (this.state.login === undefined || this.state.login == "") { this.setState({ Phonenumberisnotco:"账号不能为空", @@ -310,34 +318,35 @@ class LoginRegisterComponent extends Component { login: this.state.login, password: this.state.password, }).then((response) => { + debugger if (response === undefined) { return } if(response.data.status === -2){ - if("该手机号尚未注册" || "该邮箱尚未注册"){ - this.setState({ - Phonenumberisnotco:response.data.message, - }) - return; - } - else if("错误的账号或密码"){ - this.setState({ - Phonenumberisnotco:response.data.message, - }) - return; - } - else if("违反平台使用规范,账号已被锁定"){ - this.setState({ - Phonenumberisnotco:response.data.message, - }) - - return; - } - else { - this.openNotification(response.data.message); - return; - } + if(response.data.message==="该手机号尚未注册" || response.data.message==="该邮箱尚未注册"){ + this.setState({ + Phonenumberisnotco:response.data.message, + }) + return; + } + else if(response.data.message==="错误的账号或密码"){ + this.setState({ + Phonenumberisnotcodmms:response.data.message, + }) + return; + } + else if(response.data.message==="违反平台使用规范,账号已被锁定"){ + this.setState({ + Phonenumberisnotco:response.data.message, + }) + + return; + } + else { + this.openNotification(response.data.message); + return; + } } @@ -359,6 +368,12 @@ class LoginRegisterComponent extends Component { if(weekArray===undefined){ weekArray="/"; } + if(weekArray===null){ + weekArray="/"; + } + if(weekArray==="null"){ + weekArray="/"; + } window.location.href = weekArray; } } @@ -468,7 +483,7 @@ class LoginRegisterComponent extends Component { // }) this.setMyEduCoderModals(); } - } + } }).catch((error) => { }) @@ -489,59 +504,59 @@ class LoginRegisterComponent extends Component { // this.setState({dragOk: true}) if(result){ - if(result.data.status===-2){ - if (id === 1) { - if(result.data.message==="该手机号码或邮箱已被注册"){ - this.setState({ - Phonenumberisnotco: undefined, - Phonenumberisnotcobool: false, - dragOk:true, - }) - }else { - this.setState({ - Phonenumberisnotco: result.data.message, - Phonenumberisnotcobool: true, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - console.log("s5"); - - } - return; - } else if (id === 2) { - this.setState({ - Phonenumberisnotcos: result.data.message, - Phonenumberisnotcobool: true, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - console.log("s6"); - - return; - } - }else { - if (id === 1) { - this.setState({ - Phonenumberisnotco: undefined, - Phonenumberisnotcobool: false, - dragOk:true, - }) - return; - } else if (id === 2) { - this.setState({ - Phonenumberisnotcos: undefined, - Phonenumberisnotcobool: false, - dragOk:true, - }) - return; - } - } - } + if(result.data.status===-2){ + if (id === 1) { + if(result.data.message==="该手机号码或邮箱已被注册"){ + this.setState({ + Phonenumberisnotco: undefined, + Phonenumberisnotcobool: false, + dragOk:true, + }) + }else { + this.setState({ + Phonenumberisnotco: result.data.message, + Phonenumberisnotcobool: true, + dragOk:false, + Whethertoverify:this.state.Whethertoverify===true?false:true, + }) + console.log("s5"); + + } + return; + } else if (id === 2) { + this.setState({ + Phonenumberisnotcos: result.data.message, + Phonenumberisnotcobool: true, + dragOk:false, + Whethertoverify:this.state.Whethertoverify===true?false:true, + }) + console.log("s6"); + + return; + } + }else { + if (id === 1) { + this.setState({ + Phonenumberisnotco: undefined, + Phonenumberisnotcobool: false, + dragOk:true, + }) + return; + } else if (id === 2) { + this.setState({ + Phonenumberisnotcos: undefined, + Phonenumberisnotcobool: false, + dragOk:true, + }) + return; + } + } + } }).catch((error) => { }) - } + }; //短信验证 SMSverification = () => { var url = `/accounts/get_verification_code.json`; @@ -597,12 +612,12 @@ class LoginRegisterComponent extends Component { }) return; } - if(this.state.pciphone===true) { - if (this.state.dragOk === false) { - this.openNotification("拖动滑块验证"); - return; - } - } + if(this.state.pciphone===true) { + if (this.state.dragOk === false) { + this.openNotification("拖动滑块验证"); + return; + } + } if (this.state.getverificationcodes === true) { this.setState({ @@ -660,23 +675,26 @@ class LoginRegisterComponent extends Component { this.setState({ Phonenumberisnotco: undefined, Phonenumberisnotcobool: false, + Phonenumberisnotcodmms:undefined, login: stirngt, }) }else{ this.setState({ login: stirngt, Phonenumberisnotco:undefined, + Phonenumberisnotcodmms:undefined, }) } } //失去焦点判断 inputOnBlur = (e, id) => { - // this.isCorrectname(e.target.value, id); - // this.Emailphonenumberverification(e.target.value, id); + this.Emailphonenumberverification(e.target.value, 1); + } + inputOnBlurzhuche = (e, id) => { if (e.target.value.length === 0) { this.setState({ - Phonenumberisnotco: undefined, + Phonenumberisnotcos: undefined, Phonenumberisnotcobool: false, }) return; @@ -691,15 +709,16 @@ class LoginRegisterComponent extends Component { if (!regph.test(e.target.value)) { stringdata = "手机号格式不正确"; this.setState({ - Phonenumberisnotco: stringdata, + Phonenumberisnotcos: stringdata, Phonenumberisnotcobool: true, dragOk:false, Whethertoverify:this.state.Whethertoverify===true?false:true, }) } else { this.setState({ - Phonenumberisnotco: undefined, + Phonenumberisnotcos: undefined, Phonenumberisnotcobool: false, + }) return } @@ -712,7 +731,7 @@ class LoginRegisterComponent extends Component { } this.setState({ - Phonenumberisnotco: stringdata, + Phonenumberisnotcos: stringdata, Phonenumberisnotcobool: true, dragOk:false, Whethertoverify:this.state.Whethertoverify===true?false:true, @@ -720,70 +739,14 @@ class LoginRegisterComponent extends Component { return } else { this.setState({ - Phonenumberisnotco: undefined, + Phonenumberisnotcos: undefined, Phonenumberisnotcobool: false, + }) - this.Emailphonenumberverification(e.target.value, 1); + this.Emailphonenumberverification(e.target.value, id); return } - this.Emailphonenumberverification(e.target.value, 1); - } - inputOnBlurzhuche = (e, id) => { - if (e.target.value.length === 0) { - this.setState({ - Phonenumberisnotcos: undefined, - Phonenumberisnotcobool: false, - }) - return; - } - // var telephone = $("#telephoneAdd.tianjia_phone").val(); - var regph = /^[1][3,4,5,6,7,8][0-9]{9}$/; - // var email = $("#add_email.tianjia_email").val(); - var regemail = /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/; - - // [1]手机号开头必须是1 [3,4,5,6,7,8] 第二位是3-8中的一个 [0-9]{9} 后边9位可以是0-9的任意数字。 - var stringdata = undefined; - if (!regph.test(e.target.value)) { - stringdata = "手机号格式不正确"; - this.setState({ - Phonenumberisnotcos: stringdata, - Phonenumberisnotcobool: true, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - } else { - this.setState({ - Phonenumberisnotcos: undefined, - Phonenumberisnotcobool: false, - - }) - return - } - - if (!regemail.test(e.target.value)) { - if ((e.target.value.indexOf("@") != -1) === true) { - stringdata = "邮箱格式不正确"; - } else { - stringdata = "手机号格式不正确"; - - } - this.setState({ - Phonenumberisnotcos: stringdata, - Phonenumberisnotcobool: true, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - return - } else { - this.setState({ - Phonenumberisnotcos: undefined, - Phonenumberisnotcobool: false, - - }) - this.Emailphonenumberverification(e.target.value, id); - return - } - this.Emailphonenumberverification(e.target.value, id); + this.Emailphonenumberverification(e.target.value, id); } //获取登入密码 passwordonChange = (e) => { @@ -798,6 +761,7 @@ class LoginRegisterComponent extends Component { this.setState({ password: stirngt, Phonenumberisnotcodmm:undefined, + Phonenumberisnotcodmms:undefined, }) // this.setState({ // password: e.target.value @@ -807,28 +771,28 @@ class LoginRegisterComponent extends Component { loginInputonChanges = (e) => { console.log(e.target.value); var stirngt; - if(e.target.value.length>0){ - var str= e.target.value.replace(/\s*/g,"") - stirngt=str; - }else{ - stirngt= e.target.value; - } - if (e.target.value.length === 0) { - this.setState({ - Phonenumberisnotcos: undefined, - Phonenumberisnotcobool: false, - logins: stirngt, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - }else{ - this.setState({ - logins: stirngt, - Phonenumberisnotcos: undefined, - dragOk:false, - Whethertoverify:this.state.Whethertoverify===true?false:true, - }) - } + if(e.target.value.length>0){ + var str= e.target.value.replace(/\s*/g,"") + stirngt=str; + }else{ + stirngt= e.target.value; + } + if (e.target.value.length === 0) { + this.setState({ + Phonenumberisnotcos: undefined, + Phonenumberisnotcobool: false, + logins: stirngt, + dragOk:false, + Whethertoverify:this.state.Whethertoverify===true?false:true, + }) + }else{ + this.setState({ + logins: stirngt, + Phonenumberisnotcos: undefined, + dragOk:false, + Whethertoverify:this.state.Whethertoverify===true?false:true, + }) + } } //获取注册密码 @@ -858,7 +822,7 @@ class LoginRegisterComponent extends Component { this.setState({ tab:e.key }) - console.log(e.key); + console.log(e.key); if(e.key === 0){ this.setState({ Phonenumberisnotcos:undefined @@ -916,6 +880,7 @@ class LoginRegisterComponent extends Component { // 注册 readAgreement, pciphone, + Phonenumberisnotcodmms, } = this.state // height: 346px; if (this.state.seconds === 0) { @@ -925,30 +890,30 @@ class LoginRegisterComponent extends Component { console.log(classpass); return ( -
    - - -
    - - 登录 - 注册 - - - { - parseInt(tab[0])==0 && -
    - + +
    + + 登录 + 注册 + + + { + parseInt(tab[0])==0 && +
    + - - this.inputOnBlur(e, 1)} - style={{marginTop: '30px', height: '38px'}}> - - { - Phonenumberisnotco && Phonenumberisnotco != "" ? -

    - {Phonenumberisnotco} -

    - :
    - } - - - { - Phonenumberisnotcodmm && Phonenumberisnotcodmm != "" ? -

    - {Phonenumberisnotcodmm} -

    - :
    - } - - - - -
    - } - - - { - parseInt(tab[0])==1 && -
    - this.inputOnBlurzhuche(e, 2)} - style={{marginTop: '30px' , height: '38px',color:'#999999',fontSize:"14px"}}> - { - Phonenumberisnotcos && Phonenumberisnotcos !== "" ? -

    - {Phonenumberisnotcos} -

    - :
    + } + + + this.inputOnBlur(e, 1)} + style={{marginTop: '30px', height: '38px'}}> + + { + Phonenumberisnotco && Phonenumberisnotco != "" ? +

    + {Phonenumberisnotco} +

    + :
    + } + + + { + Phonenumberisnotcodmm && Phonenumberisnotcodmm != "" ? +

    + {Phonenumberisnotcodmm} +

    + : (Phonenumberisnotcodmms=== undefined?
    :"") + } + { + Phonenumberisnotcodmms && Phonenumberisnotcodmms != "" ? +

    + {Phonenumberisnotcodmms} +

    + : "" + } + + + + +
    + } + + + { + parseInt(tab[0])==1 && +
    + this.inputOnBlurzhuche(e, 2)} + style={{marginTop: '30px' , height: '38px',color:'#999999',fontSize:"14px"}}> + { + Phonenumberisnotcos && Phonenumberisnotcos !== "" ? +

    + {Phonenumberisnotcos} +

    + :
    + + } + {this.state.MyEduCoderModals===true? {this.setNotcompleteds()}} + />:""} + + { + Whethertoverify===false&&pciphone===true? + + + : + "" - } - {this.state.MyEduCoderModals===true? {this.setNotcompleteds()}} - />:""} - - { - Whethertoverify===false&&pciphone===true? - - - : - "" - - } - { - Whethertoverify===true&&pciphone===true? - - + } + { + Whethertoverify===true&&pciphone===true? + + : "" - } + } -
    - { - pciphone===true? - ( - Phonenumberisnotcosytdhk && Phonenumberisnotcosytdhk !== "" ? +
    + { + pciphone===true? + ( + Phonenumberisnotcosytdhk && Phonenumberisnotcosytdhk !== "" ?

    {Phonenumberisnotcosytdhk}

    :
    - ) - :"" - } -
    - - - -
    - - - - { - getverificationcodes === undefined ? - - : getverificationcodes === true ? - - : - - } - -
    -
    - { - Phonenumberisnotcosyzm && Phonenumberisnotcosyzm !== "" ? -

    - {Phonenumberisnotcosyzm} -

    - :
    + ) + :"" + } +
    + + + +
    + + + + { + getverificationcodes === undefined ? + + : getverificationcodes === true ? + + : + + } + +
    +
    + { + Phonenumberisnotcosyzm && Phonenumberisnotcosyzm !== "" ? +

    + {Phonenumberisnotcosyzm} +

    + :
    - } -
    + } +
    - - this.Showandhide(key)}> - - }> - { - Phonenumberisnotcosymmm && Phonenumberisnotcosymmm !== "" ? -

    - {Phonenumberisnotcosymmm} -

    - :
    - - } - 我已阅读并同意 + } + + this.Showandhide(key)}> + + }> + { + Phonenumberisnotcosymmm && Phonenumberisnotcosymmm !== "" ? +

    + {Phonenumberisnotcosymmm} +

    + :
    + + } + 我已阅读并同意 《服务协议条款》 - + -
    - } -
    -
    +
    + } +
    +
    ); } } diff --git a/public/react/src/modules/user/Notcompletedysl.js b/public/react/src/modules/user/Notcompletedysl.js index 8f147957a..53d9b3509 100644 --- a/public/react/src/modules/user/Notcompletedysl.js +++ b/public/react/src/modules/user/Notcompletedysl.js @@ -37,6 +37,12 @@ class Notcompletedysl extends Component { if(weekArray===undefined){ weekArray="/"; } + if(weekArray===null){ + weekArray="/"; + } + if(weekArray==="null"){ + weekArray="/"; + } window.location.href = weekArray; } @@ -46,7 +52,7 @@ class Notcompletedysl extends Component { render() { - console.log(this.props) + // console.log(this.props) return( { - (!filterDepartments || (filterDepartments && filterDepartments.length==0 ) + filterDepartments != undefined && ( (filterDepartments && filterDepartments.length==0 ) || (departmentsName == '' && !this.state.department_id && (!departments || departments.length == 0) )) &&
    diff --git a/public/react/src/modules/user/account/ChangeHeaderPicModal.js b/public/react/src/modules/user/account/ChangeHeaderPicModal.js index cef643094..76a1a2ebe 100644 --- a/public/react/src/modules/user/account/ChangeHeaderPicModal.js +++ b/public/react/src/modules/user/account/ChangeHeaderPicModal.js @@ -151,7 +151,7 @@ class ChangeHeaderPicModal extends Component{ text-align: center; width: 120px; height: 120px; - border: 1px solid #eee; + /* border: 1px solid #eee; */ } .previewWrap { flex-direction: column; diff --git a/public/react/src/modules/user/modal/ApplyForAddChildOrgModal.js b/public/react/src/modules/user/modal/ApplyForAddChildOrgModal.js index be53dbdec..db32beed3 100644 --- a/public/react/src/modules/user/modal/ApplyForAddChildOrgModal.js +++ b/public/react/src/modules/user/modal/ApplyForAddChildOrgModal.js @@ -16,7 +16,7 @@ class ApplyForAddChildOrgModal extends Component{ } componentDidUpdate=(prevState)=>{ - if(this.props.departmentName && prevState.departmentName != this.props.departmentName){ + if(prevState.departmentName != this.props.departmentName){ this.setValue(this.props.departmentName) } } diff --git a/public/react/src/modules/user/usersInfo/Infos.js b/public/react/src/modules/user/usersInfo/Infos.js index 3b58681da..f20cd5be5 100644 --- a/public/react/src/modules/user/usersInfo/Infos.js +++ b/public/react/src/modules/user/usersInfo/Infos.js @@ -17,6 +17,12 @@ import "../../courses/css/Courses.css" import Trialapplication from '../../login/Trialapplication' + +const InfosPackage = Loadable({ + loader: () => import('./InfosPackage'), + loading:Loading, +}) + const InfosCourse = Loadable({ loader: () => import('./InfosCourse'), loading:Loading, @@ -373,11 +379,17 @@ class Infos extends Component{ to={`/users/${username}/paths`}>实践课程
  • - this.setState({moduleName: 'projects'})} to={`/users/${username}/projects`}>项目
  • - + + {/*
  • */} + {/* this.setState({moduleName: 'package'})}*/} + {/*to={`/users/${username}/package`}>众包*/} + {/*
  • */} + {/*{ data && data.identity!="学生" &&
  • 题库
  • }*/}
    @@ -389,6 +401,15 @@ class Infos extends Component{ {/* --------------------------------------------------------------------- */} + + {/* 众包 */} + {/* http://localhost:3007/courses/1309/homework/9300/setting */} + () + } + > + {/* 课堂 */} {/* http://localhost:3007/courses/1309/homework/9300/setting */} () } > + + () diff --git a/public/react/src/modules/user/usersInfo/InfosCourse.js b/public/react/src/modules/user/usersInfo/InfosCourse.js index ff5321a9f..2f7d206b8 100644 --- a/public/react/src/modules/user/usersInfo/InfosCourse.js +++ b/public/react/src/modules/user/usersInfo/InfosCourse.js @@ -130,7 +130,7 @@ class InfosCourse extends Component{ this.props.current_user && this.props.current_user.user_identity != "学生" ? : "" } { - (!data || data.courses.length==0) && (this.props.current_user && this.props.current_user.user_identity === "学生" ) && + (!data || data.courses.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && } { data && data.courses && data.courses.map((item,key)=>{ @@ -147,7 +147,7 @@ class InfosCourse extends Component{ { item.can_visited ==false?
    - +

    非成员不能访问

    :"" } diff --git a/public/react/src/modules/user/usersInfo/InfosPackage.js b/public/react/src/modules/user/usersInfo/InfosPackage.js new file mode 100644 index 000000000..f1077cd62 --- /dev/null +++ b/public/react/src/modules/user/usersInfo/InfosPackage.js @@ -0,0 +1,126 @@ +import React, { Component } from 'react'; +import { SnackbarHOC } from 'educoder'; +import {BrowserRouter as Router,Route,Switch} from 'react-router-dom'; +import {Tooltip,Menu,Pagination,Spin} from 'antd'; +import Loadable from 'react-loadable'; +import Loading from '../../../Loading'; +import axios from 'axios'; +import NoneData from '../../courses/coursesPublic/NoneData' +import {getImageUrl} from 'educoder'; +import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; +import { CNotificationHOC } from '../../courses/common/CNotificationHOC' +import "./usersInfo.css" +import Create from './publicCreatNew' + +class InfosPackage extends Component{ + constructor(props){ + super(props); + this.state={ + category:undefined, + status:undefined, + page:1, + per_page:16, + + totalCount:undefined, + data:undefined, + isSpin:false + } + } + + componentDidMount=()=>{ + this.setState({ + isSpin:true + }) + let{category,status,page}=this.state; + this.getCourses(category,status,page); + } + + getCourses=(category,status,page)=>{ + let url=`/users/${this.props.match.params.username}/courses.json`; + axios.get((url),{params:{ + category, + status, + page, + per_page: this.props.is_current && category && page ==1?17:16 + }}).then((result)=>{ + if(result){ + this.setState({ + totalCount:result.data.count, + data:result.data, + isSpin:false + }) + } + }).catch((error)=>{ + console.log(error); + }) + } + + //切换种类 + changeCategory=(cate)=>{ + this.setState({ + category:cate, + page:1, + isSpin:true + }) + let{status}=this.state; + this.getCourses(cate,status,1); + } + //切换状态 + changeStatus=(status)=>{ + this.setState({ + status:status, + page:1, + isSpin:true + }) + let{category}=this.state; + this.getCourses(category,status,1); + } + //切换页数 + changePage=(page)=>{ + this.setState({ + page, + isSpin:true + }) + let{category,status}=this.state; + this.getCourses(category,status,page); + } + + // 进入课堂 + turnToCourses=(url,flag)=>{ + if(flag){ + this.props.history.push(url); + } + } + + render(){ + let{ + category, + status, + page, + data, + totalCount, + isSpin + } = this.state; + let is_current=this.props.is_current; + + console.log(this.props.current_user&&this.props.current_user.user_identity==="学生") + return( + + ) + } +} +export default InfosPackage; \ No newline at end of file diff --git a/public/react/src/modules/user/usersInfo/InfosPath.js b/public/react/src/modules/user/usersInfo/InfosPath.js index 759527a6e..d23739280 100644 --- a/public/react/src/modules/user/usersInfo/InfosPath.js +++ b/public/react/src/modules/user/usersInfo/InfosPath.js @@ -152,7 +152,7 @@ class InfosPath extends Component{ this.props.current_user && this.props.current_user.user_identity != "学生" ? :"" } { - (!data || data.subjects.length==0) && (this.props.current_user && this.props.current_user.user_identity === "学生" ) && + (!data || data.subjects.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && } { data && data.subjects && data.subjects.map((item,key)=>{ diff --git a/public/react/src/modules/user/usersInfo/InfosProject.js b/public/react/src/modules/user/usersInfo/InfosProject.js index 6c1f4a666..195e98b73 100644 --- a/public/react/src/modules/user/usersInfo/InfosProject.js +++ b/public/react/src/modules/user/usersInfo/InfosProject.js @@ -125,7 +125,7 @@ class InfosProject extends Component{ :"" } { - (!data || data.projects.length==0) && (this.props.current_user && this.props.current_user.user_identity === "学生" ) && + (!data || data.projects.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && } { data && data.projects && data.projects.map((item,key)=>{ @@ -142,7 +142,7 @@ class InfosProject extends Component{ { item.can_visited ==false?
    - +

    非成员不能访问

    :"" } diff --git a/public/react/src/modules/user/usersInfo/InfosShixun.js b/public/react/src/modules/user/usersInfo/InfosShixun.js index bac60fe6f..1550230ab 100644 --- a/public/react/src/modules/user/usersInfo/InfosShixun.js +++ b/public/react/src/modules/user/usersInfo/InfosShixun.js @@ -161,7 +161,7 @@ class InfosShixun extends Component{ :"" } { - (!data || data.shixuns.length==0) && (this.props.current_user && this.props.current_user.user_identity === "学生" ) && + (!data || data.shixuns.length==0) && (!is_current || (this.props.current_user && this.props.current_user.user_identity === "学生" )) && } { data && data.shixuns && data.shixuns.map((item,key)=>{ diff --git a/public/react/src/search/SearchPage.js b/public/react/src/search/SearchPage.js index 32d88b392..ccdb9e12a 100644 --- a/public/react/src/search/SearchPage.js +++ b/public/react/src/search/SearchPage.js @@ -164,7 +164,7 @@ class SearchPage extends Component{
    -

    没有数据可以显示!

    +

    暂时还没有相关数据哦!

    diff --git a/public/stylesheets/educoder/edu-all.css b/public/stylesheets/educoder/edu-all.css index c5831dad4..ec245b196 100644 --- a/public/stylesheets/educoder/edu-all.css +++ b/public/stylesheets/educoder/edu-all.css @@ -1,11 +1,25 @@ /*--------------------------首页*/ /*头部导航条样式---2018-03-19--by-cs*/ -.newHeader{background: #24292D !important; width:100%; height: 60px !important; min-width: 1200px;position: fixed;top: 0px;left: 0px;z-index:1000;-moz-box-shadow: 0px 0px 12px rgba(0,0,0,0.1); /* 老的 Firefox */box-shadow: 0px 0px 12px rgba(0,0,0,0.1);} +.newHeader{ + /*overflow:hidden;*/ + /*text-overflow:ellipsis;*/ + /*white-space:nowrap;*/ + background: #24292D !important; width:100%; height: 60px !important; min-width: 1200px;position: fixed;top: 0px;left: 0px;z-index:1000;-moz-box-shadow: 0px 0px 12px rgba(0,0,0,0.1); /* 老的 Firefox */box-shadow: 0px 0px 12px rgba(0,0,0,0.1); +} .newHeader .logoimg{ margin-top: 16px; float: left; width: 97px;} -.head-nav{float: left;width:830px;text-align: center;height: 60px;box-sizing: border-box; min-width: 400px;} +.head-nav{ + float: left; + text-align: center; + height: 60px; + box-sizing: border-box; + min-width: 785px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} .head-nav ul#header-nav{position: absolute;top: 0px;z-index: 3;height: 60px;box-sizing: border-box;} .head-nav ul#header-nav li{float: left;height: 60px;line-height: 60px;margin-right: 30px;cursor: pointer;position: relative;font-size: 16px} .head-nav ul#header-nav li a{display: block;height: 100%;width: 100%;color: #fff} @@ -408,7 +422,7 @@ table.text-file{} /*-------------------------------实训路径-------------------------------*/ -.path-head{width: 100%;height: 300px;background-image: url("/images/educoder/path.jpg");background-color: #081C4B;background-size: 100% 100%;} +.path-head{width: 100%;height: 300px;background-image: url("/images/educoder/path.png");background-color: #081C4B;background-size: 100% 100%;} .pathNavLine{position: absolute;bottom: -8px;width: 100%;} .path-nav li{float: left;padding: 0px 30px;height: 42px;} .path-nav li a{color:#fff;font-size: 16px;display: block; height: 40px;} @@ -3039,4 +3053,291 @@ a.singlepublishtwo{ .CourseTargetPoint tbody tr td{vertical-align: top;} .editormd-dialog-footer{ padding: 0px; +} +.project_packagesHead{width: 100%;margin-bottom:40px;background-size: 100% 100%;background-image: url("/images/educoder/project_packagesHead.jpg");height: 240px; + justify-content: center;align-items: center;display: -webkit-flex;} + + +/* 个人中心-众包 */ +.project-packages-list { +} +.project-packages-list .project-package-item { + display: -webkit-flex; + display: flex; + flex-direction: row; + margin-bottom: 20px; + padding: 20px; + background: white; + /*box-shadow:1px 3px 3px 1px rgba(156,156,156,0.16);*/ +} + +.project-packages-list .project-package-item:hover{ + box-shadow: 1px 6px 16px rgba(156,156,156,0.16); + opacity: 1; + border-radius: 2px; +} + +.project-packages-list .project-package-item .item-image { + width: 150px; + height: 110px; +} +.project-packages-list .project-package-item .item-body { + margin-left: 20px; + flex: 1; +} + +.project-package-item .item-body { + display: -webkit-flex; + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.project-package-item .item-body .item-head { + display: -webkit-flex; + display: flex; + justify-content: space-between; + font-size: 20px; + height: 40px; +} +.project-package-item .item-head-title { + max-width: 700px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: max-width .2s; + -moz-transition: max-width .2s; /* Firefox 4 */ + -webkit-transition: max-width .2s; /* Safari 和 Chrome */ + -o-transition: max-width .2s; /* Opera */ +} +.project-package-item .item-head-tags { + display: -webkit-flex; + display: flex; + align-items: center; +} +.project-package-item .item-head-tags span { + margin-left: 20px; + padding: 0 10px; + height: 28px; + font-size: 14px; + color: white; + border-radius: 5px; +} +.project-package-item .item-head-tags span.pending { background: lightcoral; } +.project-package-item .item-head-tags span.bidding_won { background: lightgreen; } +.project-package-item .item-head-tags span.bidding_lost { background: grey; } + +.project-package-item .item-head-blank { + flex: 1; +} +.project-package-item .item-head-price { + margin-left: 20px; + color: #F83B2D; + font-size: 28px; + font-weight: bold; +} +.project-package-item .item-head-price span { + font-size: 18px; +} +.project-package-item .item-category { + display: -webkit-flex; + display: flex; +} +.project-package-item .item-category-item { + padding: 0 10px; + color: #FF6800; + font-size: 14px; + background:rgba(255,235,213,1); + border-radius:13px; +} + +.project-package-item .item-other { + display: -webkit-flex; + display: flex; + justify-content: space-between; + color: #999999; +} +.project-package-item .item-group { + flex: 2; +} +.project-package-item .item-group.item-other-publish-at { + text-align: right; +} +.project-package-item .item-other-blank { + flex: 3 +} + +.project-package-item.with-operator .item-operator { + width: 0; + transition: width .2s; + -moz-transition: width .2s; /* Firefox 4 */ + -webkit-transition: width .2s; /* Safari 和 Chrome */ + -o-transition: width .2s; /* Opera */ +} +.project-package-item.with-operator:hover .item-operator { + margin: -20px -20px -20px 20px; + padding: 20px 0; + width: 100px; + display: flex; + justify-content: space-around; + flex-direction: column; + align-items: center; + background: #f0f0f0; +} +.project-package-item.with-operator .item-operator a { + display: none; +} +.project-package-item.with-operator:hover .item-operator a { + display: block; + font-size: 20px; +} +.project-package-item.with-operator:hover .item-head-title { + max-width: 600px; +} + +.list-count { + background: #fafafa; +} +.list-count span { + color: coral; + padding: 0 3px; +} + + +.applycompetitions{ + line-height: 30px; + border-radius: 14px; + color: #666; + background: rgba(41,189,139,1); + opacity: 0.8; + font-size: 14px; + font-family: MicrosoftYaHei; + font-weight: 400; + color: rgba(255,255,255,1); + position: absolute; + bottom: 139px; + left: 18px; + width: 73px; + height: 30px; + text-align: center; +} + +.noteDetailPoints{ + width: 70px; + height: 70px; + background-color: #4cacff; + border-radius: 50%; + color: #fff; + text-align: center; + margin: 0 auto; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 2px 0; + cursor: pointer; + line-height: 22px; + padding-top: 12px; +} + +.noteDetailPointsBCD1E3{ + width: 70px; + height: 70px; + background-color: #BCD1E3; + border-radius: 50%; + color: #fff; + text-align: center; + margin: 0 auto; + -webkit-box-sizing: border-box; + box-sizing: border-box; + padding: 2px 0; + cursor: pointer; + line-height: 22px; + padding-top: 12px; +} + +.-task-sidebars{ + position: fixed; + width: 40px; + height: 180px; + right: 0; + bottom: 30px; + z-index: 10; +} + +.winput150{ + width:150px; +} + + +.upload_Titles{ + position: relative; + float: left; + line-height: 35px; + font-size: 16px; + width: 50px; +} + +.lineheight35{ + line-height: 35px; +} + +.w120{ + width:120px; +} +.h90{ + width:90px; +} + +.decoration4CACFF{ + color: #4CACFF !important; + border-bottom: 1px solid #4CACFF; +} + +.surfacePlot{ + cursor: pointer; + width:122px; + height:92px; + background:rgba(250,250,250,1); + border:1px solid rgba(221,221,221,1); +} + +.marginuploading{ + padding: 28px 43px; + position: absolute; + z-index: 10; +} +.surfacePlot:hover .marginuploading.hidden{ + background: rgba(0,0,0, 0.1); +} + +.roundedRectangles { + position: absolute; + top: 10px; + right: -22px; +} + + +.edu-menu-lists .currentName{ + text-align: left; +} + +.edu-menu-lists li{ + text-align: left; +} + +.login_regs{ + width: 580px !important; +} + +.login_regs a{ + cursor: pointer; +} + +#member_block{ + height: 260px; + overflow-y: auto; +} + +#trophyreturn i{ + font-size: 16px!important; + color: #AAAAAA; } \ No newline at end of file diff --git a/spec/controllers/forums_controller_spec.rb b/spec/controllers/forums_controller_spec.rb new file mode 100644 index 000000000..a4143d232 --- /dev/null +++ b/spec/controllers/forums_controller_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ForumsController, type: :controller do + +end diff --git a/spec/helpers/forums_helper_spec.rb b/spec/helpers/forums_helper_spec.rb new file mode 100644 index 000000000..46766dbff --- /dev/null +++ b/spec/helpers/forums_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ForumsHelper. For example: +# +# describe ForumsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe ForumsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/forum_spec.rb b/spec/models/forum_spec.rb new file mode 100644 index 000000000..56c246346 --- /dev/null +++ b/spec/models/forum_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe Forum, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end