dev_cs
p31729568 5 years ago
commit 52041806fe

@ -3,6 +3,10 @@ module PaginateHelper
page = params[:page].to_i <= 0 ? 1 : params[:page].to_i page = params[:page].to_i <= 0 ? 1 : params[:page].to_i
per_page = params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : opts[:per_page] || 20 per_page = params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : opts[:per_page] || 20
if objs.is_a?(Array)
Kaminari.paginate_array(objs).page(page).per(per_page) Kaminari.paginate_array(objs).page(page).per(per_page)
else
objs.page(page).per(per_page)
end
end end
end end

@ -47,6 +47,10 @@ class Ecs::BaseController < ApplicationController
page = params[:page].to_i <= 0 ? 1 : params[:page].to_i 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 per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20
if objs.is_a?(Array)
Kaminari.paginate_array(objs).page(page).per(per_page) Kaminari.paginate_array(objs).page(page).per(per_page)
else
objs.page(page).per(per_page)
end
end end
end end

@ -15,19 +15,31 @@ class Ecs::EcGraduationRequirementsController < Ecs::BaseController
end end
def create def create
graduation_requirement = current_year.graduation_requirements.new graduation_requirement = current_year.ec_graduation_requirements.new
@graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params) @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params)
render 'show' render 'show'
end end
def update def update
graduation_requirement = current_year.graduation_requirements.find(params[:id]) @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(current_graduation_requirement, update_params)
@graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, update_params)
render 'show' render 'show'
end end
def destroy
ActiveRecord::Base.transaction do
current_graduation_requirement.destroy!
current_year.ec_graduation_requirements.where('position > ?', current_graduation_requirement.position)
.update_all('position = position - 1')
end
render_ok
end
private private
def current_graduation_requirement
@_current_graduation_requirement ||= current_year.ec_graduation_requirements.find(params[:id])
end
def create_params def create_params
params.permit(:position, :content, graduation_subitems: [:content]) params.permit(:position, :content, graduation_subitems: [:content])
end end

@ -1,4 +1,6 @@
class Ecs::EcMajorSchoolsController < Ecs::BaseController class Ecs::EcMajorSchoolsController < Ecs::BaseController
skip_before_action :check_user_permission!, only: [:show]
def index def index
major_schools = current_school.ec_major_schools.not_template major_schools = current_school.ec_major_schools.not_template
@ -20,7 +22,18 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController
@count = major_schools.count #检索后的数量,小于或等于全部数量 @count = major_schools.count #检索后的数量,小于或等于全部数量
@major_schools = paginate(major_schools.includes(:users, :ec_major)) @major_schools = paginate(major_schools.includes(:users, :ec_major))
@template_major_school = current_school.ec_major_schools.is_template.first #示例专业 @template_major_school = EcMajorSchool.is_template.first #示例专业
end
# :show是 /api/ec_major_schools/:id
def show
@major = EcMajorSchool.find(params[:id])
school = @major.school
return if current_user.admin? || school.manager?(current_user)
return if @major.manager?(current_user)
render_forbidden
end end
def create def create

@ -1,7 +1,7 @@
class Ecs::EcMajorsController < Ecs::BaseController class Ecs::EcMajorsController < Ecs::BaseController
def index def index
school_major_subquery = current_school.ec_major_schools.select(:ec_major_id) #学校已选择的专业 @major_ids = current_school.ec_major_schools.pluck(:ec_major_id) #学校已选择的专业
ec_majors = EcMajor.where.not(id: school_major_subquery) ec_majors = EcMajor.all
if params[:search].present? if params[:search].present?
ec_majors = ec_majors.search_name_or_code(params[:search]) ec_majors = ec_majors.search_name_or_code(params[:search])

@ -2,7 +2,7 @@ class Ecs::EcTrainingObjectivesController < Ecs::BaseController
before_action :check_major_manager_permission!, only: [:create] before_action :check_major_manager_permission!, only: [:create]
def show def show
@training_objective = current_year.ec_training_objective @training_objective = current_year.ec_training_objective || current_year.build_ec_training_objective
respond_to do |format| respond_to do |format|
format.json format.json

@ -10,7 +10,7 @@ class Ecs::EcYearsController < Ecs::BaseController
end end
@count = ec_years.count @count = ec_years.count
@ec_years = paginate ec_years @ec_years = paginate ec_years.order(year: :desc)
return if @ec_years.blank? return if @ec_years.blank?
@ -27,13 +27,17 @@ class Ecs::EcYearsController < Ecs::BaseController
.where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count .where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count
end end
def show
@year = current_year
end
def create def create
if current_major_school.ec_years.exists?(year: params[:year].to_i) if current_major_school.ec_years.exists?(year: params[:year].to_i)
render_error('届别已存在') render_error('届别已存在')
return return
end end
@ec_year = CopyEcYearService.call(current_major_school, params[:year].to_i) @ec_year = Ecs::CopyEcYearService.call(current_major_school, params[:year].to_i)
end end
def destroy def destroy

@ -3,7 +3,8 @@ class Ecs::MajorManagersController < Ecs::BaseController
before_action :check_manager_permission! before_action :check_manager_permission!
def create def create
@user = Ecs::CreateMajorManagerService.call(current_major_school, params[:user_id]) Ecs::CreateMajorManagerService.call(current_major_school, params[:user_ids])
render_ok
rescue Ecs::CreateMajorManagerService::Error => ex rescue Ecs::CreateMajorManagerService::Error => ex
render_error(ex.message) render_error(ex.message)
end end

@ -14,5 +14,13 @@ class Ecs::ReachEvaluationsController < Ecs::BaseController
end end
def create def create
relations = current_year.ec_graduation_requirements.joins(ec_graduation_subitems: :ec_course_support)
ec_course_ids = relations.pluck('ec_course_supports.ec_course_id').uniq
EcCourse.where(id: ec_course_ids).each do |ec_course|
Ecs::CalculateCourseEvaluationService.call(ec_course)
end
render_ok
end end
end end

@ -0,0 +1,22 @@
class Ecs::UsersController < Ecs::BaseController
skip_before_action :check_user_permission!
before_action :check_manager_permission!
def index
users = UserQuery.call(params)
@count = users.count
@users = paginate users.includes(user_extension: [:school, :department])
@manager_ids = current_major_school.ec_major_school_users.pluck(:user_id)
end
private
def current_major_school
@_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id])
end
def current_school
@_current_school ||= current_major_school.school
end
end

@ -55,7 +55,13 @@ class Users::BaseController < ApplicationController
page = page_value page = page_value
per_page = per_page_value per_page = per_page_value
return Kaminari.paginate_array(objs).page(page).per(per_page) unless opts[:special] && observed_logged_user? unless opts[:special] && observed_logged_user?
if objs.is_a?(Array)
return Kaminari.paginate_array(objs).page(page).per(per_page)
else
return objs.page(page).per(per_page)
end
end
# note: 为实现第一页少一条记录,让前端放置新建入口 # note: 为实现第一页少一条记录,让前端放置新建入口
if page == 1 if page == 1

@ -0,0 +1,22 @@
module Ecs::EcYearsHelper
def achieved_graduation_course_count(ec_year)
return 0 if ec_year.ec_courses.count.zero?
course_ids = ec_year.ec_courses.map(&:id)
target_count_map = EcCourseTarget.where(ec_course_id: course_ids).group(:ec_course_id).count
ec_year.ec_courses.sum { |course| course.complete_target_count == target_count_map[course.id] ? 1 : 0 }
end
def achieved_graduation_objective_count(ec_year)
return 0 if ec_year.ec_graduation_subitems.count.zero?
subitem_ids = ec_year.ec_graduation_subitems.reorder(nil).pluck(:id)
relations = EcGraduationRequirementCalculation.joins(:ec_course_support).where(ec_course_supports: { ec_graduation_subitem_id: subitem_ids })
reached_map = relations.where(status: true).group('ec_graduation_subitem_id').count
reached_map.keys.size
end
end

@ -45,6 +45,8 @@ module Util
def conceal(str, type = nil) def conceal(str, type = nil)
str = str.to_s str = str.to_s
return if str.blank?
case type case type
when :phone then "#{str[0..2]}***#{str[-4..-1]}" when :phone then "#{str[0..2]}***#{str[-4..-1]}"
when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}" when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}"

@ -1,7 +1,6 @@
class EcCourseStudentScore < ApplicationRecord class EcCourseStudentScore < ApplicationRecord
belongs_to :ec_year_student belongs_to :ec_year_student
belongs_to :ec_course belongs_to :ec_course
belongs_to :ec_course_target
has_many :ec_student_score_targets, dependent: :delete_all has_many :ec_student_score_targets, dependent: :delete_all
end end

@ -1,9 +1,10 @@
class EcCourseSupport < ApplicationRecord class EcCourseSupport < ApplicationRecord
default_scope { order(position: :asc) } default_scope { order(position: :asc) }
alias_attribute :weights, :weigths
belongs_to :ec_course belongs_to :ec_course
belongs_to :ec_graduation_subitem belongs_to :ec_graduation_subitem
# TODO: 将 ec_graduation_subitem_courses 移除,这个表作为关系表
has_one :ec_graduation_requirement_calculation, dependent: :destroy has_one :ec_graduation_requirement_calculation, dependent: :destroy

@ -1,4 +1,3 @@
# TODO:: change table column :weigths => :weight
class EcCourseTarget < ApplicationRecord class EcCourseTarget < ApplicationRecord
belongs_to :ec_course belongs_to :ec_course
@ -8,6 +7,8 @@ class EcCourseTarget < ApplicationRecord
has_many :ec_course_achievement_methods, dependent: :destroy has_many :ec_course_achievement_methods, dependent: :destroy
has_many :ec_achievement_evaluation_relates, dependent: :destroy has_many :ec_achievement_evaluation_relates, dependent: :destroy
alias_attribute :weight, :weigths
validates :content, presence: true validates :content, presence: true
validates :standard_grade, numericality: { only_integer: true, greater_than: 0 } validates :standard_grade, numericality: { only_integer: true, greater_than: 0 }
validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 } validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 }

@ -1,4 +1,6 @@
class EcGraduationRequirement < ApplicationRecord class EcGraduationRequirement < ApplicationRecord
default_scope { order(position: :asc) }
belongs_to :ec_year belongs_to :ec_year
has_many :ec_graduation_subitems, dependent: :destroy has_many :ec_graduation_subitems, dependent: :destroy
@ -7,5 +9,5 @@ class EcGraduationRequirement < ApplicationRecord
validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 }
validates :content, presence: true validates :content, presence: true
default_scope { order(position: :asc) } accepts_nested_attributes_for :ec_graduation_subitems, allow_destroy: true
end end

@ -12,6 +12,8 @@ class EcMajorSchool < ApplicationRecord
scope :is_template, -> { where(template_major: true) } scope :is_template, -> { where(template_major: true) }
scope :not_template, -> { where(template_major: false) } scope :not_template, -> { where(template_major: false) }
delegate :code, :name, to: :ec_major
# 是否为该专业管理员 # 是否为该专业管理员
def manager?(user) def manager?(user)
ec_major_school_users.exists?(user_id: user.id) ec_major_school_users.exists?(user_id: user.id)

@ -1,4 +1,6 @@
class EcTrainingSubitem < ApplicationRecord class EcTrainingSubitem < ApplicationRecord
default_scope { order(position: :asc) }
belongs_to :ec_training_objective belongs_to :ec_training_objective
has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy

@ -9,4 +9,11 @@ class EcYear < ApplicationRecord
has_many :ec_graduation_requirements, dependent: :destroy has_many :ec_graduation_requirements, dependent: :destroy
has_many :ec_graduation_subitems, through: :ec_graduation_requirements has_many :ec_graduation_subitems, through: :ec_graduation_requirements
has_many :ec_year_students, dependent: :destroy has_many :ec_year_students, dependent: :destroy
has_many :ec_course_users, dependent: :destroy
has_many :managers, through: :ec_course_users, source: :user
def prev_year
self.class.find_by(year: year.to_i - 1)
end
end end

@ -1,3 +1,9 @@
class ApplicationQuery class ApplicationQuery
include Callable include Callable
private
def strip_param(key)
params[key].to_s.strip.presence
end
end end

@ -0,0 +1,28 @@
class UserQuery < ApplicationQuery
attr_reader :params
def initialize(params)
@params = params
end
def call
users = User.where(type: 'User')
# 真实姓名
if name = strip_param(:name)
users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%")
end
# 单位名称
if school = strip_param(:school)
users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school}%")
end
# 职业
if (identity = strip_param(:identity)) && UserExtension.identities.keys.include?(identity)
users = users.joins(:user_extension).where(user_extensions: { identity: identity })
end
users
end
end

@ -1,4 +1,4 @@
class CopyEcYearService < ApplicationService class Ecs::CopyEcYearService < ApplicationService
attr_reader :major_school, :to_year attr_reader :major_school, :to_year
def initialize(major_school, year) def initialize(major_school, year)

@ -27,7 +27,7 @@ class Ecs::CreateCourseService < ApplicationService
private private
def create_default_score_levels!(ec_course) def create_default_score_levels!(ec_course)
EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position) do |worker| EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position, :created_at, :updated_at) do |worker|
[ [
{ ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 }, { ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 },
{ ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 }, { ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 },

@ -3,29 +3,30 @@ class Ecs::CreateMajorManagerService < ApplicationService
MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制 MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制
attr_reader :major_school, :user_id attr_reader :major_school, :user_ids
def initialize(major_school, user_id) def initialize(major_school, user_ids)
@major_school = major_school @major_school = major_school
@user_id = user_id @user_ids = user_ids
end end
def call def call
raise Error, '示例专业不能添加管理员' if major_school.template_major? raise Error, '示例专业不能添加管理员' if major_school.template_major?
user = User.find_by(id: params[:user_id]) @user_ids = User.where(id: user_ids).pluck(:id)
raise Error, '该用户不存在' if user.blank?
if major_school.ec_major_school_users.exists?(user_id: user.id) if major_school.ec_major_school_users.exists?(user_id: user_ids)
raise Error, '该用户已经是该专业的管理员了' raise Error, '所选用户中存在该专业的管理员'
end end
if major_school.ec_major_school_users.count >= MAJOR_MANAGER_COUNT_LIMIT if major_school.ec_major_school_users.count + user_ids.count > MAJOR_MANAGER_COUNT_LIMIT
raise Error, '该专业管理员数量已达上限' raise Error, "该专业管理员数量超过上限(#{MAJOR_MANAGER_COUNT_LIMIT}人)"
end end
major_school.ec_major_school_users.create!(user: user) ActiveRecord::Base.transaction do
user_ids.each do |user_id|
user major_school.ec_major_school_users.create!(user_id: user_id)
end
end
end end
end end

@ -11,13 +11,16 @@ class Ecs::CreateTrainingObjectiveService < ApplicationService
def call def call
training_objective.content = params[:content].to_s.strip training_objective.content = params[:content].to_s.strip
if params.key?(:training_subitems)
attributes = build_accepts_nested_attributes( attributes = build_accepts_nested_attributes(
training_objective, training_objective,
training_objective.ec_training_subitems, training_objective.ec_training_subitems,
params[:training_subitems], params[:training_subitems],
&method(:training_subitem_param_handler) &method(:training_subitem_param_handler)
) )
attributes.each_with_index { |attr, index| attr[:position] = index + 1 }
training_objective.assign_attributes(ec_training_subitems_attributes: attributes) training_objective.assign_attributes(ec_training_subitems_attributes: attributes)
end
training_objective.save! training_objective.save!
training_objective training_objective

@ -17,12 +17,12 @@ class Ecs::QueryCourseEvaluationService < ApplicationService
end end
def graduation_subitem_evaluations def graduation_subitem_evaluations
student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) student_scores = ec_course.ec_course_student_scores.joins(ec_student_score_targets: :ec_course_target).group(:ec_course_target_id)
student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id')
student_score_map = student_scores.group_by { |item| item.ec_course_target_id } student_score_map = student_scores.group_by { |item| item.ec_course_target_id }
subitem_targets = ec_course.ec_graduation_subitem_course_targets subitem_targets = ec_course.ec_graduation_subitem_course_targets
.includes(ec_graduation_subitem: :ec_graduation_requirement) .includes(:ec_course_target, ec_graduation_subitem: :ec_graduation_requirement)
subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr| subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr|
subitem = arr.first.ec_graduation_subitem subitem = arr.first.ec_graduation_subitem
@ -37,7 +37,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService
arr.map(&:ec_course_target).uniq.each do |target| arr.map(&:ec_course_target).uniq.each do |target|
target_total_rates += target.weight.to_f target_total_rates += target.weight.to_f
student_score = student_score_map[target.id] student_score = student_score_map[target.id]&.first
reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score
end end
@ -60,8 +60,19 @@ class Ecs::QueryCourseEvaluationService < ApplicationService
def score_levels_map def score_levels_map
@_score_levels_map ||= begin @_score_levels_map ||= begin
index = 0
ec_course.ec_score_levels.each_with_object({}) do |level, obj| ec_course.ec_score_levels.each_with_object({}) do |level, obj|
obj[level.id.to_s] = level.as_json(only: %i[id position score level]) hash = level.as_json(only: %i[id position score level])
hash[:description] =
case index
when 0 then "#{level.score}分以上"
when ec_course.ec_score_levels.to_a.size - 1 then "低于#{level.score}"
else "#{level.score}~#{ec_course.ec_score_levels[index - 1].score - 1}"
end
index += 1
obj[level.id.to_s] = hash
end end
end end
end end
@ -87,23 +98,29 @@ class Ecs::QueryCourseEvaluationService < ApplicationService
@_course_achievement += data[:average_score].to_f * course_target.weight.to_f @_course_achievement += data[:average_score].to_f * course_target.weight.to_f
# 计算学生成绩分布区间 # 计算学生成绩分布区间
student_count = 0
data[:score_levels] = score_levels.map do |score_level| data[:score_levels] = score_levels.map do |score_level|
level_condition_proc = level_condition_proc =
if (score_level.position - 1).zero? # 第一区间 if (score_level.position - 1).zero? # 第一区间
-> (score_target){ score_target.score >= score_level.score ? 1 : 0 } -> (score_target){ score_target.score >= score_level.score ? 1 : 0 }
elsif score_levels.position == score_levels.size # 末尾区间 elsif score_level.position == score_levels.size # 末尾区间
-> (score_target){ score_target.score < score_level.score ? 1 : 0 } -> (score_target){ score_target.score < score_level.score ? 1 : 0 }
else else
# 中间区间 # 中间区间
-> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 } -> (score_target){ score_target.score >= score_level.score && score_target.score < score_levels[score_level.position - 1].score ? 1 : 0 }
end end
# 计算该成绩区间人数 # 计算该成绩区间人数
count = score_targets.sum(&level_condition_proc) count = score_targets.sum(&level_condition_proc)
student_count += count
{ id: score_level.id, count: count } { id: score_level.id, count: count }
end end
data[:score_levels].each do |score_level|
score_level[:rate] = score_level[:count].fdiv(student_count).round(2)
end
data data
end end
end end

@ -13,7 +13,7 @@ wb.styles do |style|
name = course_evaluation.name name = course_evaluation.name
items_size = course_evaluation.ec_course_evaluation_subitems.count items_size = course_evaluation.ec_course_evaluation_subitems.count
sheet.add_row name, style: bg_style sheet.add_row [name], style: bg_style
sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))] sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))]
data = [] data = []

@ -1 +1 @@
json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation', as: :ec_course_evaluation json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation', as: :ec_course_evaluation

@ -1 +1 @@
json.partial! 'shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation

@ -1 +1 @@
json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation_slim', as: :ec_course_evaluation json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation

@ -1,2 +1,2 @@
json.course_targets @course_targets, partial: 'shared/course_target', as: :ec_course_target json.course_targets @course_targets, partial: 'ecs/course_targets/shared/course_target', as: :ec_course_target

@ -15,7 +15,7 @@ wb.styles do |style|
name = "#{@_current_course.name}课程目标" name = "#{@_current_course.name}课程目标"
wb.add_worksheet(name: name) do |sheet| wb.add_worksheet(name: name) do |sheet|
sheet.add_row name, style: title_style sheet.add_row [name], style: title_style
sheet.add_row [] sheet.add_row []
sheet.add_row [] sheet.add_row []

@ -1,2 +1,2 @@
json.count @count json.count @count
json.ec_courses @ec_courses, partial: 'shared/ec_course_slim', as: :ec_course json.ec_courses @ec_courses, partial: 'ecs/ec_courses/shared/ec_course_slim', as: :ec_course

@ -1,3 +1,3 @@
json.count @graduation_requirements.size json.count @graduation_requirements.size
json.graduation_requirements @graduation_requirements, partial: 'shared/ec_graduation_requirement', as: :ec_graduation_requirement json.graduation_requirements @graduation_requirements, partial: '/ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement

@ -6,15 +6,15 @@ wb = xlsx_package.workbook
wb.styles do |style| wb.styles do |style|
title_style = style.add_style(sz: 16, height: 20, b: true) title_style = style.add_style(sz: 16, height: 20, b: true)
ec_year_style = style.add_style(sz: 10, height: 14) ec_year_style = style.add_style(sz: 10, height: 14)
label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center, vertical: :center })
content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' })
wb.add_worksheet(:name => '毕业要求及指标点') do |sheet| wb.add_worksheet(:name => '毕业要求及指标点') do |sheet|
sheet.add_row '毕业要求及指标点', style: title_style sheet.add_row ['毕业要求及指标点'], style: title_style
sheet.add_row [] sheet.add_row []
sheet.add_row ['专业代码', major.code], style: ec_year_style sheet.add_row ['专业代码', major.code.to_s + ' '], style: ec_year_style
sheet.add_row ['专业名称', major.name], style: ec_year_style sheet.add_row ['专业名称', major.name], style: ec_year_style
sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style
@ -32,12 +32,15 @@ wb.styles do |style|
end end
items_size = requirement.ec_graduation_subitems.size items_size = requirement.ec_graduation_subitems.size
sheet.merge_cells("A#{index}:A#{index + items_size}") if items_size.zero?
sheet.merge_cells("B#{index}:B#{index + items_size}") sheet.add_row [requirement_content, ''], style: content_style
else
sheet.merge_cells("A#{index + 1}:A#{index + items_size}")
end
index += items_size index += items_size
end end
sheet.column_widths [400, 400] sheet.column_widths 100, 100
end end
end end

@ -1,2 +1,2 @@
json.partial! 'shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement json.partial! 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement

@ -3,7 +3,7 @@ json.count @count
# 示例专业 # 示例专业
json.template_ec_major_school do json.template_ec_major_school do
json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school if @template_major_school
end end
# 专业 # 专业
@ -11,5 +11,5 @@ json.ec_major_schools @major_schools do |ec_major_school|
json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school
# 专业管理员 # 专业管理员
json.major_managers ec_major_school.users, partial: 'ecs/ec_major_schools/shared/ec_major_school', as: :user json.major_managers ec_major_school.users, partial: 'users/user_simple', as: :user
end end

@ -0,0 +1,6 @@
json.extract! @major, :id, :code, :name, :template_major
json.school_id @major.school.id
json.school_name @major.school.name
can_manager = @major.manager?(current_user) || @major.school.manager?(current_user) || current_user.admin_or_business?
json.can_manager can_manager

@ -1,2 +1,7 @@
json.count @count json.count @count
json.es_majors @ec_majors, partial: 'ecs/majors/shared/ec_major', as: :ec_major json.ec_majors do
json.array! @ec_majors.each do |major|
json.extract! major, :id, :name, :code
json.selected @major_ids.include?(major.id)
end
end

@ -1,3 +1,3 @@
json.extract! ec_training_objective, :id, :content json.extract! ec_training_objective, :id, :content
json.ec_training_items ec_training_objective.ec_training_subitems, partial: 'ec_training_subitem', as: :ec_training_subitem json.ec_training_items ec_training_objective.ec_training_subitems, partial: '/ecs/ec_training_objectives/shared/ec_training_subitem', as: :ec_training_subitem

@ -1 +1 @@
json.partial! 'shared/ec_training_objective', ec_training_objective: @training_objective json.partial! '/ecs/ec_training_objectives/shared/ec_training_objective', ec_training_objective: @training_objective

@ -6,11 +6,11 @@ wb = xlsx_package.workbook
wb.styles do |style| wb.styles do |style|
title_style = style.add_style(sz: 16, height: 20, b: true) title_style = style.add_style(sz: 16, height: 20, b: true)
ec_year_style = style.add_style(sz: 10, height: 14) ec_year_style = style.add_style(sz: 10, height: 14)
label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', border: { style: :thin, color: '000000' }, alignment: { horizontal: :center, vertical: :center })
content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' })
wb.add_worksheet(:name => '培养目标及目标分解') do |sheet| wb.add_worksheet(:name => '培养目标及目标分解') do |sheet|
sheet.add_row '培养目标及目标分解', style: title_style sheet.add_row ['培养目标及目标分解'], style: title_style
sheet.add_row [] sheet.add_row []
sheet.add_row [] sheet.add_row []
@ -27,6 +27,6 @@ wb.styles do |style|
end end
items_size = training_objective.ec_training_subitems.size items_size = training_objective.ec_training_subitems.size
sheet.merge_cells("A9:A#{9 + items_size}") sheet.merge_cells("A9:A#{9 + items_size - 1}")
end end
end end

@ -8,7 +8,16 @@ json.ec_years do
json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0) json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0)
json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0) json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0)
json.course_count @course_count_map.fetch(ec_year.id, 0) json.course_count @course_count_map.fetch(ec_year.id, 0)
json.course_target_count @course_target_count_map.fetch(ec_year.id, 0)
json.graduation_subitem_count @graduation_subitem_count_map.fetch(ec_year.id, 0) course_target = @course_target_count_map.fetch(ec_year.id, 0)
graduation_subitem = @graduation_subitem_count_map.fetch(ec_year.id, 0)
achieved_course = achieved_graduation_course_count(ec_year)
achieved_objective = achieved_graduation_objective_count(ec_year)
json.course_target_count course_target
json.graduation_subitem_count graduation_subitem
json.achieved_graduation_course_count achieved_course
json.achieved_graduation_objective_count achieved_objective
json.status graduation_subitem == achieved_objective ? 'achieved' : 'not_achieved'
end end
end end

@ -0,0 +1,13 @@
json.extract! @year, :id, :year
major = @year.ec_major_school
json.major_id major.id
json.major_name major.name
json.major_code major.code
school = major.school
json.school_id school.id
json.school_name school.name
can_manager = major.manager?(current_user) || school.manager?(current_user) || current_user.admin_or_business?
json.can_manager can_manager

@ -1 +1 @@
json.partial! 'shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem json.partial! 'ecs/graduation_course_supports/shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem

@ -3,3 +3,4 @@ json.extract! ec_graduation_subitem, :id, :position, :content, :ec_graduation_re
json.graduation_requirement_position ec_graduation_subitem.ec_graduation_requirement.position json.graduation_requirement_position ec_graduation_subitem.ec_graduation_requirement.position
json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ec_course_support', as: :ec_course_support json.course_supports ec_graduation_subitem.ec_course_supports, partial: 'ec_course_support', as: :ec_course_support
json.weights_total ec_graduation_subitem.ec_course_supports.to_a.sum(&:weights)

@ -1,3 +1,3 @@
json.course_count @course_count json.course_count @course_count
json.graduation_subitems @graduation_subitems, partial: 'shared/ec_graduation_subitem', as: :ec_graduation_subitem json.graduation_subitems @graduation_subitems, partial: 'ecs/graduation_course_supports/shared/ec_graduation_subitem', as: :ec_graduation_subitem
json.count @graduation_subitems.size json.count @graduation_subitems.size

@ -14,7 +14,7 @@ wb.styles do |style|
tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A') tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A')
wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet| wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet|
sheet.add_row '课程体系VS毕业要求', style: title_style sheet.add_row ['课程体系VS毕业要求'], style: title_style
sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))] sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))]
sheet.add_row [] sheet.add_row []

@ -13,4 +13,4 @@ json.school do
json.name current_school.name json.name current_school.name
end end
json.school_managers @school_managers, partial: 'ecs/shared/user', as: :user json.school_managers @school_managers, partial: 'users/user_simple', as: :user

@ -1 +0,0 @@
json.partial! 'ecs/shared/user', user: @user

@ -10,7 +10,7 @@ wb.styles do |style|
content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' })
wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet| wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet|
sheet.add_row '培养目标及目标分解', style: title_style sheet.add_row ['达成度-毕业要求综合评价报表'], style: title_style
sheet.merge_cells("A1:D1") sheet.merge_cells("A1:D1")
sheet.add_row [] sheet.add_row []

@ -1,4 +1,4 @@
json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement
json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem
json.requirement_support_objectives @requirement_support_objectives, partial: 'shared/requirement_support_objective', as: :requirement_support_objective json.requirement_support_objectives @requirement_support_objectives, partial: 'ecs/requirement_support_objectives/shared/requirement_support_objective', as: :requirement_support_objective

@ -16,7 +16,7 @@ wb.styles do |style|
content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' })
wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet| wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet|
sheet.add_row '毕业要求 vs 培养目标矩阵', style: title_style sheet.add_row ['毕业要求 vs 培养目标矩阵'], style: title_style
sheet.merge_cells wb.rows.first.cells[(1..subitem_size)] sheet.merge_cells wb.rows.first.cells[(1..subitem_size)]

@ -1 +1 @@
json.score_levels @score_levels, partial: 'shared/ec_score_level', as: :ec_score_level json.score_levels @score_levels, partial: 'ecs/score_levels/shared/ec_score_level', as: :ec_score_level

@ -1,2 +1,2 @@
json.count @count json.count @count
json.students @students, partial: 'shared/ec_year_student', as: :ec_year_student json.students @students, partial: 'ecs/students/shared/ec_year_student', as: :ec_year_student

@ -1,4 +1,4 @@
json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard
json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem
json.subitem_support_standards @subitem_support_standards, partial: 'shared/subitem_support_standard', as: :subitem_support_standard json.subitem_support_standards @subitem_support_standards, partial: 'ecs/subitem_support_standards/shared/subitem_support_standard', as: :subitem_support_standard

@ -17,7 +17,7 @@ wb.styles do |style|
content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' })
wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet| wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet|
sheet.add_row '毕业要求 vs 通用标准矩阵', style: title_style sheet.add_row ['毕业要求 vs 通用标准矩阵'], style: title_style
sheet.merge_cells wb.rows.first.cells[(1..standards_size)] sheet.merge_cells wb.rows.first.cells[(1..standards_size)]

@ -0,0 +1,12 @@
json.count @count
json.users do
json.array! @users.each do |user|
json.id user.id
json.name user.real_name
json.identity user.identity
json.school_name user.school_name
json.department_name user.department_name
json.phone Util.conceal(user.phone, :phone)
json.manager @manager_ids.include?(user.id)
end
end

@ -710,14 +710,15 @@ Rails.application.routes.draw do
# 为避免url过长以及层级过深路由定义和controller继承都做了处理 # 为避免url过长以及层级过深路由定义和controller继承都做了处理
scope module: :ecs do scope module: :ecs do
resources :ec_major_schools, only: [] do resources :ec_major_schools, only: [:show] do
resources :users, only: [:index]
resources :major_managers, only: [:create, :destroy] resources :major_managers, only: [:create, :destroy]
resources :ec_years, only: [:index, :create, :destroy] resources :ec_years, only: [:index, :show, :create, :destroy]
end end
resources :ec_years, only: [] do resources :ec_years, only: [] do
resource :ec_training_objectives, only: [:show, :create] resource :ec_training_objectives, only: [:show, :create]
resources :ec_graduation_requirements, only: [:index, :create] resources :ec_graduation_requirements, only: [:index, :create, :update, :destroy]
resource :requirement_support_objectives, only: [:show, :create, :destroy] resource :requirement_support_objectives, only: [:show, :create, :destroy]
resource :subitem_support_standards, only: [:show, :create, :destroy] resource :subitem_support_standards, only: [:show, :create, :destroy]
resource :students, only: [:show, :destroy] do resource :students, only: [:show, :destroy] do

@ -0,0 +1,11 @@
class ChangeEcCourseSupports < ActiveRecord::Migration[5.2]
def change
add_column :ec_course_supports, :ec_graduation_subitem_id, :integer, index: true
execute <<-SQL
UPDATE ec_course_supports ecs SET ec_graduation_subitem_id = (
SELECT ec_graduation_subitem_id FROM ec_graduation_subitem_courses egsc WHERE egsc.ec_course_support_id = ecs.id
)
SQL
end
end

@ -32,7 +32,7 @@ module.exports = {
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s
// devtool: "cheap-module-eval-source-map", // devtool: "cheap-module-eval-source-map",
// 开启调试 // 开启调试
devtool: "eval", // 开启调试 // devtool: "eval", // 开启调试
// These are the "entry points" to our application. // These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle. // This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS. // The first two entry points enable "hot" CSS and auto-refreshes for JS.
@ -197,6 +197,21 @@ module.exports = {
}, },
], ],
}, },
{
test: /\.scss$/,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
},
},
{
loader: require.resolve("sass-loader")
}
],
},
// "file" loader makes sure those assets get served by WebpackDevServer. // "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename. // When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder. // In production, they would get copied to the `build` folder.

@ -224,6 +224,23 @@ module.exports = {
), ),
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`. // Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
}, },
{
test: /\.scss$/,
use: [
require.resolve("style-loader"),
{
loader: require.resolve("css-loader"),
options: {
importLoaders: 1,
minimize: true,
sourceMap: shouldUseSourceMap,
},
},
{
loader: require.resolve("sass-loader")
}
],
},
// "file" loader makes sure assets end up in the `build` folder. // "file" loader makes sure assets end up in the `build` folder.
// When you `import` an asset, you get its filename. // When you `import` an asset, you get its filename.
// This loader doesn't use a "test" so it will catch all modules // This loader doesn't use a "test" so it will catch all modules

@ -5,7 +5,7 @@
"dependencies": { "dependencies": {
"@icedesign/base": "^0.2.5", "@icedesign/base": "^0.2.5",
"@novnc/novnc": "^1.1.0", "@novnc/novnc": "^1.1.0",
"antd": "^3.20.1", "antd": "^3.23.2",
"array-flatten": "^2.1.2", "array-flatten": "^2.1.2",
"autoprefixer": "7.1.6", "autoprefixer": "7.1.6",
"axios": "^0.18.0", "axios": "^0.18.0",
@ -163,6 +163,8 @@
"babel-plugin-import": "^1.11.0", "babel-plugin-import": "^1.11.0",
"concat": "^1.0.3", "concat": "^1.0.3",
"happypack": "^5.0.1", "happypack": "^5.0.1",
"node-sass": "^4.12.0",
"sass-loader": "^7.3.1",
"webpack-bundle-analyzer": "^3.0.3", "webpack-bundle-analyzer": "^3.0.3",
"webpack-parallel-uglify-plugin": "^1.1.0" "webpack-parallel-uglify-plugin": "^1.1.0"
} }

@ -262,6 +262,11 @@ const Help = Loadable({
loading: Loading, loading: Loading,
}) })
const Ecs = Loadable({
loader: () => import('./modules/ecs/Ecs'),
loading: Loading,
})
class App extends Component { class App extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
@ -475,6 +480,10 @@ class App extends Component {
render={ render={
(props)=>(<Help {...this.props} {...props} {...this.state}></Help>) (props)=>(<Help {...this.props} {...props} {...this.state}></Help>)
}/> }/>
<Route path="/ecs"
render={
(props)=>(<Ecs {...this.props} {...props} {...this.state}></Ecs>)
}/>
<Route exact path="/" component={ShixunsHome}/> <Route exact path="/" component={ShixunsHome}/>
<Route component={Shixunnopage}/> <Route component={Shixunnopage}/>

@ -10,7 +10,7 @@ broadcastChannelOnmessage('refreshPage', () => {
}) })
function locationurl(list){ function locationurl(list){
debugger
if (window.location.port === "3007") { if (window.location.port === "3007") {
} else { } else {
@ -50,7 +50,6 @@ export function initAxiosInterceptors(props) {
// wy // wy
// proxy="http://192.168.2.63:3001" // proxy="http://192.168.2.63:3001"
// 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求 // 在这里使用requestMap控制避免用户通过双击等操作发出重复的请求
// 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制 // 如果需要支持重复的请求考虑config里面自定义一个allowRepeat参考来控制
const requestMap = {}; const requestMap = {};

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

@ -0,0 +1,352 @@
.eaSystemp a{
color:#05101a;
}
.eaSystemp span{
color: #05101a !important;
}
.eacourse p{
height:84px;
margin-bottom:0px !important;
}
.eacourse #training_objective_contents{
height:81px;
}
.courseSystem{
font-size:18px;
font-family:MicrosoftYaHei;
font-weight:400;
line-height:45px;
color:rgba(5,16,26,1);
}
.SystemParameters{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
line-height:45px;
color:rgba(50,50,50,1);
}
.Systemnum{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
color:#FF6800;
}
.newSystem{
width:1200px;
overflow:auto;
background: #FFF;
}
.newSystem .clearfix .column-1{
width: 113px !important;
text-align: center;
}
.operationColumn{
margin: 0px 10%;
width:100%;
height:100%;
}
.operationalter{
margin: 20px 16px;
}
.SystemModifythelist .column-1{
width: 120px !important;
text-align: center;
}
.SystemModifythelist .column-3{
padding-left: 96px;
margin-right: 23px;
}
.operationright{
float:right !important;
}
.newSystem p{
/*padding: 10px 33px !important;*/
margin-bottom: 0em;
}
.newSystem li{
margin:0 !important;
}
.SystemModifythelist{
background:#FFF !important;
}
.SystemModifythelist .column-1:nth-child(1){
margin-left: 7px;
}
.Systempoint{
font-size:12px;
font-family:MicrosoftYaHei;
font-weight:400;
color:rgba(152,152,152,1);
}
.editorModify{
background:#FFF !important;
}
.newSystem .editorModify .column-1{
width: 194px !important;
text-align: left;
margin-left: 30px;
}
.newSystem .editorModify .column-1:nth-child(1){
margin-right: 510px;
}
.editorModify .ant-select{
width: 556px !important;
margin-left: 36px;
}
.editorModify .ant-select .ant-select-selection{
height: 30px !important;
}
.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered{
height: 30px !important;
}
.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered .ant-select-selection-selected-value{
line-height: 30px !important;
}
.inputWeight{
width: 20%;
font-size:14px;
height:30px;
margin-left: 20px;
background-color: #F5F5F5;
}
.SetTheAssociated{
width: 314px;
height: 30px;
float: right;
margin-right: -3.5%;
}
.SetTheAssociatedchild{
width: 120px;
height: 30px;
background: rgba(255,255,255,1);
border: 1px solid rgba(234,234,234,1);
border-radius: 4px;
float: left;
margin-right: 10px;
text-align: center;
line-height: 30px;
/*margin-left: 34px;*/
}
.operatebutton{
margin-left: 20px;
/* margin-top: 16px; */
}
.editbulebutton{
width:120px;
height:30px;
background:rgba(76,172,255,1);
border-radius:2px;
color:#FFF;
text-align: center;
line-height: 30px;
}
.editglybutton{
width:120px;
height:30px;
border:1px solid rgba(205,205,205,1);
border-radius:2px;
color:#999;
text-align: center;
line-height: 30px;
}
.editglybuttonbox{
width: 275px;
margin-bottom: 30px;
margin-right: 20px;
margin-right:7%;
}
.editglybuttonboxs{
width: 275px;
margin-bottom: 30px;
margin-right: 20px;
margin-right:3%;
}
.defalutCancelbtn:hover {
border: 1px solid #B2B2B2;
color: #B2B2B2!important;
}
.gouxuanbule{
color:#4CACFF;
}
.gouxuanwhite{
color:#FFF;
}
.icon-gouxuan{
cursor: pointer;
}
/* 谷歌 */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
}
/* 火狐 */
input{
-moz-appearance:textfield;
}
.inputWeight{
text-indent:0.625rem;
}
.columnlocation{
height: 40px;
line-height: 40px;
}
.paddingLF{
padding:0 33px;
}
.width20{
width: 20px;
height: 20px;
text-align: center;
}
.defalutSubmitbtn,.defalutCancelbtn{
cursor: pointer;
}
.mb290{
margin-bottom:290px;
}
.Spinlarge{
text-align: center;
width: 100%;
margin-top: 25px;
margin-bottom: 25px;
}
.DDred{
color:#DD1717;
}
.color-666{
color:#666666 !important;
}
.color-05101A{
color:#05101A !important;
}
.ec_graduation_name{
margin-right:20px !important;
}
.column-width575{
color: transparent !important;
}
.column-width130{
width: 130px !important;
height: 40px;
}
.ListTableLine li>span {
max-width: 550px !important;
}
.graduateRequirement .clearfix .column-1 {
width: 76px!important;
}
.newrightcalculatebutton{
width: 50px;
height: 25px;
border: 1px solid rgba(76,172,255,1);
border-radius: 1px;
line-height: 25px;
text-align: center;
margin-top: 7px;
cursor: pointer;
color: rgba(76,172,255,1);
}
.columnbox{
height: 53px;
overflow: hidden;
}
.ant-modal-mask {
background-color: rgba(5,16,26,0.4);
}
.ecmodeldelet{
top:300px;
}
.ecmodeldelet .ant-modal-header{
padding: 0px 24px;
}
.ecmodeldelet .ant-modal-title{
padding: 0px 15px;
text-align: center;
box-sizing: border-box;
line-height: 70px;
height: 70px;
border-radius: 10px 10px 0px 0px;
font-size: 16px;
font-weight: bold;
}
.bor-red {
border: 1px solid #db0505 !important;
}
.ml93{
margin-left:93px;
}
.ml26{
margin-left: 26px;
}
.finishtarget{
width: 69px;
/* height: 48px; */
line-height: 20px;
text-align: center;
margin-right: 48px;
}
.bordereaeaea{
border-bottom: 1px solid transparent !important;
}
.heightimportant{
height: 30px !important;
background-color: #F5F5F5;
}
.heightimportant:focus {
background-color: #fff;
}
.inputWeight:focus {
background-color: #fff;
}
.heightlineimportant{
line-height: 30px !important;
}
.ant-select-selection:hover{
border-color: #d9d9d9 !important;
}
.ant-input:focus {
outline: 0;
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-input{
border-color: #d9d9d9 !important;
}
.ant-select-selection:focus{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-select-selection:active{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-select-selection:focus{
border-color: #d9d9d9 !important;
}
.ant-select-selection{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.mt60{
margin-top:60px;
}

@ -0,0 +1,594 @@
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
import axios from 'axios';
import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd';
import './ecCourseSupports.css';
const $ = window.$;
class CourseSupports extends Component {
constructor(props) {
super(props)
this.state={
data:'',
ec_courses_list:[],
editcourse:[{"weigths": 0,
"ec_course_name":'',
"top_relation": false,
"ec_course_id":''
}],
editnum:0,
index:0,
ec_graduation_subitem_id:0,
ec_year_id:0,
schooldata:{},
spinning:true,
ecComponentState:'ecCourseSupports',
supportid:null,
Editkey:null,
titlemessage:"提示",
Supportstype:false,
Supportslist:'',
Supportssum:false,
Supportsclass:false
}
}
componentWillMount(){
this.setState({
ec_year_id:this.props.match.params.ec_year_id,
major_school_id:this.props.match.params.major_school_id
})
window.document.title = '课程体系 vs 毕业要求';
}
UpdateClassData=()=>{
let ec_year_id=this.props.match.params.ec_year_id;
this.setState({
ec_year_id:ec_year_id
})
const url = `/ec_years/${ec_year_id}/graduation_course_supports.json`;
axios.get(url)
.then((response) => {
if(response.status===200){
this.setState({
data:response.data
})
}
if(response.data.graduation_subitems.length===0){
this.setState({
Supportstype:true,
Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据'
})
}
})
.catch(function (error) {
console.log(error);
});
}
componentDidMount(){
this.setState({
ec_year_id:this.props.match.params.ec_year_id,
major_school_id:this.props.match.params.major_school_id
})
this.UpdateClassData();
}
EditSupportCourse=(key,e)=>{
$('#school_major_list').scrollLeft(0);
let id=e.target.id;
id=parseInt(id);
let subindex =e.target.getAttribute("subindex");
const url = `/ec_course_supports/edit_require_vs_course?subitem_id=`+id
axios.get(url)
.then((response) => {
if(response.status===200){
var support_data;
if(response.data.edit_support_data.length>0){
support_data=response.data.edit_support_data;
}else if(response.data.edit_support_data.length===0){
support_data=[{weights: 0,top_relation: false,ec_course_name:'',ec_course_id:''}];
}
this.setState({
ec_courses_list:response.data.ec_courses_list,
editcourse:support_data,
index:subindex,
ec_graduation_subitem_id:id,
Supportssum:false,
Supportsclass:false,
})
let {editcourse} =this.state;
let neweditcourse=editcourse;
let newnum=0;
for(var j=0;j<neweditcourse.length;j++){
if(neweditcourse[j].weigths===undefined){
newnum=0
}else{
newnum=newnum+neweditcourse[j].weigths;
}
}
newnum= Math.round(newnum*100)/100;
this.setState({
editnum:newnum
})
}
})
.catch(function (error) {
console.log(error);
});
this.setState({
Editkey:key
})
// $("#school_ListTableLine").show();
// let offsettop=$("#school_ListTableLine").position().top||$("#school_ListTableLine").scrollTop || $("#school_ListTableLine").pageYOffset;
// window.scrollTo(0, offsettop)
}
Addcourse=(e)=>{
let {editcourse} =this.state;
let neweditcourse=editcourse;
let newadd = {weigths: 0,top_relation: false,ec_course_name:'',ec_course_id:''};
neweditcourse.push(newadd);
this.setState({
editcourse:neweditcourse
})
}
editcourse=(neweditcourse)=>{
this.setState({
editcourse:neweditcourse
})
}
Deletcourse=(e)=>{
// 删除
// let id =e.target.getAttribute("index");
let {editcourse} = this.state;
let neweditcourse=editcourse;
neweditcourse.splice(e,1);
let newnum=0;
for(var j=0;j<neweditcourse.length;j++){
if(neweditcourse[j].weigths===undefined){
newnum=0
}else{
newnum=newnum+neweditcourse[j].weigths;
}
}
newnum= Math.round(newnum*100)/100;
this.setState({
Supportstype:false,
supportid:null,
Supportslist:"",
editcourse:neweditcourse,
editnum:newnum
})
}
enterweight=(e)=>{
let {editcourse} = this.state;
let neweditcourse=editcourse;
var id=e.target.id;
var value=parseFloat(e.target.value);
if(isNaN(value)){
value=""
}
var x = String(value).indexOf('.') + 1;
var y = String(value).length - x;
if(y > 2){
this.setState({
// Supportstype:true,
Supportslist:'请精确到2位数',
Supportssum:true
})
return
}
const person = new Object ();
person.weigths=value;
person.ec_course_id= neweditcourse[id].ec_course_id;
person.ec_course_name=neweditcourse[id].ec_course_name;
person.top_relation=neweditcourse[id].top_relation;
neweditcourse[id]=person;
let newnum=0;
for(var j=0;j<neweditcourse.length;j++){
if(neweditcourse[j].weigths===undefined){
newnum=newnum+0;
}else if(neweditcourse[j].weigths===""){
newnum=newnum+0;
}else{
newnum=newnum+neweditcourse[j].weigths;
}
}
newnum= Math.round(newnum*100)/100;
this.setState({
editnum:newnum,
editcourse:neweditcourse
})
if(newnum>1){
this.setState({
// Supportstype:true,
Supportslist:'权重之和不能大于1',
Supportssum:true
})
}
}
handleChange=(e)=> {
let {editcourse} = this.state;
let value=`${e[0]}`;
value=parseInt(value)
let neweditcourse=editcourse;
let num=`${e[1]}`;
num=parseInt(num)
for(var z=0;z<editcourse.length;z++){
if(neweditcourse[z].ec_course_name===`${e[2]}`){
this.setState({
Supportstype:true,
Supportslist:"请勿选择重复的支持课程"
})
return
}
}
for(var i=0;i<1;i++){
neweditcourse[num].ec_course_id=value;
neweditcourse[num].ec_course_name=`${e[2]}`
}
this.editcourse(neweditcourse);
}
relevancetop=(e)=>{
let {editcourse} = this.state;
let neweditcourse=editcourse;
let id =e.target.getAttribute("itindex");
for(var i=0;i<1;i++){
neweditcourse[id].top_relation=false;
}
this.editcourse(neweditcourse);
}
relevancebottom=(e)=>{
let {editcourse} = this.state;
let neweditcourse=editcourse;
let id =e.target.getAttribute("itindex");
for(var i=0;i<1;i++){
neweditcourse[id].top_relation=true;
}
this.editcourse(neweditcourse);
}
focus() {
this.inputNumberRef.focus();
}
blur() {
this.inputNumberRef.blur();
}
CancelSupports=()=>{
this.setState({
Editkey:null,
Supportssum:false,
Supportsclass:false,
})
}
SubmitClassData=()=>{
let {editcourse,editnum,ec_graduation_subitem_id,ec_year_id} = this.state;
if(editcourse.length===0){
this.setState({
// Supportstype:true,
Supportslist:'保存失败,至少保留一个课程',
Supportssum:true
})
return
}
if(editnum>1||editnum===0){
this.setState({
// Supportstype:true,
Supportslist:'保存失败,权重大于1或为空',
Supportssum:true
})
return
}
for(var p=0; p<editcourse.length;p++){
if(editcourse[p].weigths===""){
editcourse[p].weigths=0;
}
if(editcourse[p].ec_course_id===""){
this.setState({
// Supportstype:true,
Supportslist:'保存失败,课程不能为空',
Supportsclass:true
})
return
}
}
var Url = '/ec_course_supports';
axios.post(Url, {
ec_year_id: ec_year_id,
ec_graduation_subitem_id:ec_graduation_subitem_id,
course: editcourse
},
{
withCredentials: true
}
).then((response) => {
if(response.data.status===0){
this.setState({
Editkey:null,
Supportslist:response.data.messsage,
Supportstype:true,
Supportssum:false,
Supportsclass:false,
})
this.UpdateClassData();
}else if(response.data.status===-1){
this.setState({
Supportslist:"参数错误",
Supportstype:true,
Supportssum:false,
Supportsclass:false,
})
}
}).catch((error) => {
console.log(error)
})
}
Deletcourses=(key)=>{
this.setState({
supportid:key,
Supportslist:"您确定要删除吗?",
Supportstype:true
})
}
hideSupports=()=>{
this.setState({
Supportstype:false,
supportid:null,
Supportslist:"",
})
}
render() {
const Option = Select.Option;
let {data,ec_courses_list,editcourse,editnum,index,ec_year_id,schooldata,ecComponentState,hidesupport,supportid,Editkey,titlemessage,Supportstype,Supportslist,Supportssum,Supportsclass,major_school_id} = this.state;
var list = (length) => {
var res = [];
for(var i = 0; i < length; i++) {
res.push( <span key={i} className="column-1 color-666">
<div style={{lineHeight: '20px'}}>支撑课程
<br/> 权值
</div>
</span>)
}
return res
}
return (
<div className="newMain clearfix">
<Modal
title={titlemessage}
// Supportstype
visible={Supportstype}
className={"ecmodeldelet"}
closable={false}
footer={null}
>
<div className="task-popup-content">
<div className="task-popup-text-center font-14">{Supportslist}</div>
</div>
<div className="task-popup-submit clearfix">
<a onClick={this.hideSupports} className="task-btn fl">取消</a>
{ supportid===null?<a className="task-btn task-btn-orange fr"
onClick={this.hideSupports}
>确定</a>:
<a className="task-btn task-btn-orange fr"
onClick={()=>this.Deletcourse(supportid)}
>确定</a>}
</div>
</Modal>
<div className="educontent mb290">
<div className="edu-back-white eacourse">
<div className="clearfix padding20-30 bor-bottom-greyE" style={{position:'relative'}}>
<span className="font-18 courseSystem">课程体系对毕业要求的支撑</span>
{/* <a href="javascript:void(0)" className="fr white-btn edu-blueback-btn mt4">导出培养目标</a> */}
<span className={data.is_manager===false?"none":"Importclassroomdata"} style={{top: '29px'}}>
<a className="white-btn edu-blueback-btn fr mb10 mr10" target="_blank" href={'/ec_major_schools/'+major_school_id+'/academic_years/'+ec_year_id+'/export_course_requirements?format=xls'}>导出课程体系支撑矩阵</a>
</span>
<div className="color-grey-9 mr10">用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 <a className={"color-blue"} onClick={() => window.elasticLayer(3534)} >查看详情</a></div>
</div>
<div className="padding20-30" id="training_objective_contents">
<span className="fl SystemParameters" >毕业要求指标点<a href={data.subitems_url}><span className="Systemnum">{data.subitems_count}</span></a></span>
<span className="fl ml20 SystemParameters">课程体系<a href={data.course_url}><span className="Systemnum">{data.course_count}</span></a></span>
</div>
</div>
<div className="ListTableLine" id="school_major_list" style={{overflow:'auto'}}>
<p className="clearfix" style={{width: 120*data.max_support_count>1200? 140*data.max_support_count : 1200+"px"}}>
<span className="color-666 finishtarget">毕业要求指标点</span>
{list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)}
<span className="column-1 operationright color-666"
style={{
paddingLeft: '28px'
}}
>合计</span>
</p>
<div className="paddingLF" style={{background:'#fff'}}>
{
data.graduation_subitems===undefined? <Spin delay={500} className="Spinlarge" indicator={<Icon type="loading" style={{ fontSize: 30 }} spin />}/>:data.graduation_subitems.map((item,key)=>{
return (
<li className={data.graduation_subitems.length===key+1?"clearfix mb10":"clearfix"} key={key} style={{width: 120*data.max_support_count > 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}>
<Tooltip placement="bottom" title={item.sequence_title}>
<span className="column-1 columnlocation" style={{display:Editkey!=key?"block":'none',width: '95px', paddingLeft: '23px'}}>{item.sequence_num}</span>
</Tooltip>
{
item.course_supports.map((t,kes)=>{
return(
<span key={kes} className="column-1"
style={{
display:Editkey!=key?"block":'none',
marginRight: '-1px'
}}>
<div data-tip-down={t.name} className={t.top_relation===true?"DDred columnbox":"columnbox"}
style={{textAlign: 'center'}}
>{t.name.length>12?t.name.substring(0, 10)+"...":t.name}</div>
<div className={t.top_relation===true?"DDred":""}
style={{textAlign: 'center'}}
>{t.weigths}</div>
</span>
)
})
}
<span className="column-1 operationright" style={{display:Editkey!=key?"block":'none',width:'75px'}}>
<div className="operationColumn">
<div className="left">
<div className="width20 columnbox">{item.course_supports.length}</div>
<div className="width20">{Math.round(item.weights_total*100)/100===0?0:(Math.round(item.weights_total*100)/100)}</div>
</div>
<div className="left operationalter">
{data.is_manager===false?"":<a className="editSubentry" data-tip-down="编辑">
<i className="iconfont icon-bianjidaibeijing color-green" id={item.ec_graduation_subitem_id} subindex={item.sequence_num} onClick={this.EditSupportCourse.bind(this,key)}></i>
</a>}
</div>
</div>
</span>
<p className="ListTableLine" id="school_ListTableLine" style={{width: '1134px',display:Editkey===key?"block":'none'}} >
<p className="clearfix SystemModifythelist">
<span className="ml6" style={{width:'77px'}}>指标点 {index}</span>
<span className="column-4">支撑课程</span>
<span className="column-2 ml93">
<span> 权重(=1)</span>
<span className="Systempoint">精确到两位小数</span>
</span>
<span className="column-1 ml50">关联度最高</span>
</p>
<div className="clearfix editorModify">
{
editcourse.map((it,key)=>{
return(
<div className="mb15" key={key}>
<Select className={Supportsclass===true?"bor-red heightimportant":"heightimportant"} showSearch value={it.ec_course_name} onChange={this.handleChange}>
{
ec_courses_list.map((qva,qk)=>{
return(
<Option value={[qva.id,key,qva.name]} key={qk}>{qva.name}</Option>
)
})
}
</Select>
<Input
type="number"
size="large"
className={Supportssum===true?"inputWeight bor-red":"inputWeight"}
id={key}
value={it.weigths}
onInput={this.enterweight.bind(this)}
/>
<div className="SetTheAssociated">
<div className="SetTheAssociatedchild">
<i className="iconfont icon-gouxuan gouxuanbule" style={{display:it.top_relation===false?'none':'block'}} itindex={key} onClick={this.relevancetop.bind(this)}></i>
<i className="iconfont icon-gouxuan gouxuanwhite" style={{display:it.top_relation===false?'block':'none'}} itindex={key} onClick={this.relevancebottom.bind(this)}></i>
</div>
<div className="left operatebutton">
<a className="mr15 delSubentry" data-tip-down="删除">
<i className="iconfont icon-shanchu color-grey-c font-15" onClick={()=>this.Deletcourses(key)}></i>
</a>
<a className="newAddSubentry" data-tip-down="添加"
style={{display:key===editcourse.length-1?"inline-block":'none'}}
><i className="iconfont icon-tianjiafangda color-green" onClick={this.Addcourse}></i></a>
</div>
</div>
</div>
)
})
}
</div>
<span className="c_red none ml35" id="error_tip" style={{display:Supportssum===true||Supportsclass===true?'inline':'none'}}>{Supportslist}</span>
<div className="clearfix editorModify">
<span className="column-1"
style={{
width: '580px',
paddingLeft: '37px',
display: 'inline-block'
}}
>合计: <span>{editcourse.length}</span></span>
<span className="ml30">合计: <span>{editnum}</span></span>
</div>
<div className="right editglybuttonboxs">
<div className="defalutSubmitbtn fr" onClick={this.SubmitClassData}>保存</div>
<div className="defalutCancelbtn fr mr20" onClick={this.CancelSupports}>取消</div>
</div>
</p>
</li>
)
})
}
</div>
</div>
</div>
</div>
);
}
}
export default CourseSupports ;

@ -0,0 +1,384 @@
import React from 'react';
import PropTypes from "prop-types";
import { Link } from 'react-router-dom';
import { Spin, Button, Input, Divider, Icon, Tooltip, Form, message, Modal } from 'antd';
import axios from 'axios';
import _ from 'lodash'
import './index.scss';
const { confirm } = Modal;
class GraduationRequirement extends React.Component {
constructor (props) {
super(props);
this.state = {
loading: true,
editIndex: null,
addState: false,
submitState: false,
validateState: false,
currentEditReq: {},
newRequirement: {},
graduationRequirements: []
}
}
componentDidMount() {
this.getData();
}
getData = () => {
let { yearId } = this.props;
this.setState({ loading: true });
axios.get(`/ec_years/${yearId}/ec_graduation_requirements.json`).then(res => {
if(res.status === 200){
this.setState({
graduationRequirements: res.data.graduation_requirements,
loading: false
})
}
}).catch(e => console.log(e))
}
showDeleteConfirm = (id) => {
if(this.state.editIndex !== null || this.state.addState){
message.error('请先保存其它内容');
return
}
confirm({
title: '确认删除该毕业要求?',
okText: '确认',
cancelText: '取消',
onOk: () => {
this.deleteRequirement(id);
},
onCancel() {},
});
}
deleteRequirement = (id) => {
let { yearId } = this.props;
let url = `/ec_years/${yearId}/ec_graduation_requirements/${id}.json`;
axios.delete(url).then(res => {
if(res){
message.success('操作成功');
this.getData();
}
}).catch(e => console.log(e))
}
showEditContent = (index) => {
let { editIndex, graduationRequirements } = this.state;
if(editIndex !== null){
message.error('请先保存其它内容');
return
}
this.setState({ editIndex: index, currentEditReq: _.cloneDeep(graduationRequirements[index])})
}
onEditContentChange = (e) => {
let { currentEditReq } = this.state;
currentEditReq.content = e.target.value;
this.setState({ currentEditReq });
}
onEditItemContentChange = (e, index) => {
let { currentEditReq } = this.state;
currentEditReq.ec_graduation_subitems[index].content = e.target.value;
this.setState({ currentEditReq });
}
addEditItem = () => {
let { currentEditReq } = this.state;
currentEditReq.ec_graduation_subitems.push({id: null, content: ''})
this.setState({ currentEditReq });
}
removeEditItem = (index) => {
let { currentEditReq } = this.state;
currentEditReq.ec_graduation_subitems.splice(index, 1);
this.setState({ currentEditReq });
}
saveContentEdit = () => {
let { currentEditReq } = this.state;
let contentExist = currentEditReq.content && currentEditReq.content.length !== 0;
let errorItem = currentEditReq.ec_graduation_subitems.find(item => !item.content || item.content.length === 0);
this.setState({ validateState: !!errorItem || !contentExist });
if(errorItem || !contentExist){ return }
this.setState({ submitState: true }, this.updateRequirement);
}
cancelContentEdit = () => {
this.setState({ currentEditReq: {}, editIndex: null, validateState: false });
}
updateRequirement = () => {
let { yearId } = this.props;
let { currentEditReq } = this.state;
let url = `/ec_years/${yearId}/ec_graduation_requirements/${currentEditReq.id}.json`;
axios.put(url, { content: currentEditReq.content, position: currentEditReq.position, graduation_subitems: currentEditReq.ec_graduation_subitems }).then(res => {
if(res){
message.success('操作成功');
this.setState({ submitState: false, editIndex: null });
this.getData();
}
}).catch(e => {
console.log(e);
this.setState({ submitState: false });
})
}
showNewReqContent = () => {
let { editIndex, graduationRequirements } = this.state;
if(editIndex !== null){
message.error('请先保存其它内容');
return
}
this.setState({
editIndex: -1, addState: true,
newRequirement: {
content: '', position: graduationRequirements.length + 1,
graduation_subitems: [
{ id: null, content: '' },
{ id: null, content: '' },
{ id: null, content: '' },
]
}
})
}
onNewReqContentChange = (e) => {
let { newRequirement } = this.state;
newRequirement.content = e.target.value;
this.setState({ newRequirement });
}
onNewReqItemContentChange = (e, index) => {
let { newRequirement } = this.state;
newRequirement.graduation_subitems[index].content = e.target.value;
this.setState({ newRequirement });
}
addNewReqItem = () => {
let { newRequirement } = this.state;
newRequirement.graduation_subitems.push({id: null, content: ''})
this.setState({ newRequirement });
}
removeNewReqItem = (index) => {
let { newRequirement } = this.state;
newRequirement.graduation_subitems.splice(index, 1);
this.setState({ newRequirement });
}
saveNewReq = () => {
let { newRequirement } = this.state;
let contentExist = newRequirement.content && newRequirement.content.length !== 0;
let errorItem = newRequirement.graduation_subitems.find(item => !item.content || item.content.length === 0);
this.setState({ validateState: !!errorItem || !contentExist });
if(errorItem || !contentExist){ return }
this.setState({ submitState: true }, this.createRequirement);
}
cancelNewReq = () => {
this.setState({ newRequirement: {}, addState: false, editIndex: null, validateState: false });
}
createRequirement = () => {
let { yearId } = this.props;
let { newRequirement } = this.state;
let url = `/ec_years/${yearId}/ec_graduation_requirements.json`;
axios.post(url, newRequirement).then(res => {
if(res){
message.success('操作成功');
this.setState({ submitState: false, editIndex: null, addState: false });
this.getData();
}
}).catch(e => {
console.log(e);
this.setState({ submitState: false });
})
}
render() {
let { can_manager } = this.props.year;
let { loading, editIndex, addState, submitState, validateState, currentEditReq, graduationRequirements, newRequirement } = this.state;
return (
<div>
<Spin spinning={loading} size='large' style={{ marginTop: '15%' }}>
<div className="educontent ec-graduation-requirement-page">
<div className="ec-head">
<div className="ec-head-left">
<div className="ec-head-label">毕业要求(及其指标点)</div>
<div className="ec-head-tip">
<span>请结合本专业特色修改毕业要求文字描述及指标点需完全覆盖12项通用标准</span>
<Link to="/forums/3530" target="_blank" className="link ml10">查看详情</Link>
</div>
</div>
<a href={`/api/ec_years/${this.props.yearId}/ec_graduation_requirements.xlsx`} target="_blank" className="ant-btn ant-btn-primary color-white">导出毕业要求</a>
</div>
<Divider/>
<div className="graduation-requirement-body">
<div className="graduation-requirement-items">
<div className="graduation-requirement-items-head">
<div className="no-column">指标点</div>
<div className="item-content-column">内容</div>
<div className="operation-column">
{
can_manager && !addState && (
<Tooltip title="添加">
<Icon type="plus-circle" className="edit-action" onClick={this.showNewReqContent} />
</Tooltip>
)
}
</div>
</div>
<div className="graduation-requirement-items-body">
{
graduationRequirements && graduationRequirements.map((item, index) => {
return can_manager && index === editIndex ? (
<div className="graduation-requirement-items-body-item active" key={index}>
<div className="item-row item-head">
<div className="no-column">{ index + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!currentEditReq.content || currentEditReq.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={currentEditReq.content} onChange={this.onEditContentChange} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.addEditItem}/></Tooltip>
</div>
</div>
{
currentEditReq.ec_graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ index + 1 }-{ i + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!subitem.content || subitem.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={subitem.content} onChange={(e) => this.onEditItemContentChange(e, i)} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.removeEditItem(i)}/></Tooltip>
</div>
</div>
)
})
}
<div className="edit-form">
<Button type="primary" loading={submitState} onClick={this.saveContentEdit}>保存</Button>
<Button disabled={submitState} onClick={this.cancelContentEdit}>取消</Button>
</div>
</div>
) : (
<div className="graduation-requirement-items-body-item" key={index}>
<div className="item-row item-head">
<div className="no-column">{ index + 1 }</div>
<div className="item-content-column">{ item.content }</div>
{
can_manager && (
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.showDeleteConfirm(item.id)} /></Tooltip>
<Tooltip title="编辑"><Icon type="edit" theme="filled" className="edit-action" onClick={() => this.showEditContent(index)}/></Tooltip>
{
index === graduationRequirements.length - 1 && !addState && (
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.showNewReqContent}/></Tooltip>
)
}
</div>
)
}
</div>
{
item.ec_graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ index + 1 }-{ i + 1 }</div>
<div className="item-content-column">{ subitem.content }</div>
</div>
)
})
}
</div>
)
})
}
{
can_manager && addState && (
<div className="graduation-requirement-items-body-item active">
<div className="item-row item-head">
<div className="no-column">{ graduationRequirements.length + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!newRequirement.content || newRequirement.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={newRequirement.content} onChange={this.onNewReqContentChange} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.addNewReqItem}/></Tooltip>
</div>
</div>
{
newRequirement.graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ graduationRequirements.length + 1 }-{ i + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!subitem.content || subitem.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={subitem.content} onChange={(e) => this.onNewReqItemContentChange(e, i)} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.removeNewReqItem(i)}/></Tooltip>
</div>
</div>
)
})
}
<div className="edit-form">
<Button type="primary" loading={submitState} onClick={this.saveNewReq}>保存</Button>
<Button disabled={submitState} onClick={this.cancelNewReq}>取消</Button>
</div>
</div>
)
}
</div>
</div>
</div>
</div>
</Spin>
</div>
)
}
}
GraduationRequirement.propTypes = {
schoolId: PropTypes.string,
majorId: PropTypes.string,
yearId: PropTypes.string,
}
export default GraduationRequirement

@ -0,0 +1,94 @@
.ec-graduation-requirement-page {
background: #fff;
.graduation-requirement {
&-body {
margin-top: -24px;
}
&-items {
&-head {
padding: 15px 30px;
display: flex;
background: #F5F5F5;
}
&-body {
margin: 0 30px;
&-item {
padding: 10px 0px;
border-bottom: 1px solid #eaeaea;
&.active {
.item-row {
margin-bottom: 10px;
align-items: center;
}
.item-column-operation {
width: 40px;
}
}
&:last-child {
border-bottom: unset;
}
.item-head {
margin-bottom: 10px;
font-weight: bold;
}
.item-row {
display: flex;
}
}
}
.no-column {
width: 60px;
text-align: center;
}
.item-content-column {
flex: 1;
padding-left: 10px;
display: flex;
.ant-form-item {
flex: 1;
margin-bottom: 0;
}
}
.item-column-operation {
display: flex;
justify-content: flex-end;
width: 80px;
& > i {
margin: 0 5px;
font-size: 16px;
cursor: pointer;
}
}
}
}
.edit-form {
margin-top: 10px;
text-align: right;
button {
margin-left: 10px;
}
}
i.edit-action {
color: #29BD8B;
cursor: pointer;
font-size: 16px;
}
}

@ -0,0 +1,264 @@
import React from 'react';
import PropTypes from "prop-types";
import { Link } from 'react-router-dom';
import { Spin, Button, Input, Divider, Icon, Tooltip, Form, message } from 'antd';
import axios from 'axios';
import './index.scss';
class TrainingObjective extends React.Component {
constructor (props) {
super(props);
this.state = {
loading: true,
contentEditState: false,
itemsEditState: false,
submitState: false,
validateState: false,
itemSubmitState: false,
itemValidateState: false,
objective: {},
editContent: '',
trainingSubitems: []
}
}
componentDidMount() {
this.getData();
}
getData = () => {
let { yearId } = this.props;
axios.get(`/ec_years/${yearId}/ec_training_objectives.json`).then(res => {
if(res.status === 200){
this.setState({
objective: res.data,
editContent: res.data.content,
trainingSubitems: res.data.ec_training_items,
loading: false
})
}
}).catch(e => console.log(e))
}
saveContentEdit = () => {
let { editContent } = this.state;
this.setState({ validateState: editContent.length === 0 });
if(editContent.length === 0){ return; }
this.setState(
{ submitState: true },
() => {
this.updateTrainingObjective(
{ content: editContent },
() => {
this.setState({ submitState: false, contentEditState: false });
this.getData();
},
_e => {
this.setState({ submitState: false })
}
)
}
);
}
cancelContentEdit = () => {
this.setState({ editContent: this.state.objective.content, contentEditState: false });
}
editItemsContent = () => {
let { trainingSubitems } = this.state;
if(!trainingSubitems || trainingSubitems.length === 0){
trainingSubitems = [{ id: null, content: null }]
}
this.setState({ trainingSubitems: trainingSubitems, itemsEditState: true });
}
addItemColumn = (index) => {
let { trainingSubitems } = this.state;
trainingSubitems.splice(index, 0, { id: null, content: null });
this.setState({ trainingSubitems })
}
removeItemColumn = (index) => {
let { trainingSubitems } = this.state;
trainingSubitems.splice(index, 1);
this.setState({ trainingSubitems })
}
onItemContentChange = (e, index) => {
let { trainingSubitems } = this.state;
trainingSubitems[index].content = e.target.value;
this.setState({ trainingSubitems: trainingSubitems });
}
saveItemsContentEdit = () => {
let { objective, trainingSubitems } = this.state;
let errorItem = trainingSubitems.find(item => !item.content || item.content.length === 0);
this.setState({ itemValidateState: !!errorItem });
if(errorItem){ return }
this.setState(
{ itemSubmitState: true },
() => {
this.updateTrainingObjective(
{ content: objective.content, training_subitems: trainingSubitems },
() => {
this.setState({ itemSubmitState: false, itemsEditState: false });
this.getData();
},
_e => {
this.setState({ itemSubmitState: false })
}
)
}
);
}
cancelItemsContentEdit = () => {
this.setState({ trainingSubitems: this.state.objective.ec_training_items, itemsEditState: false, itemValidateState: false });
}
updateTrainingObjective = (data, success, fail) => {
let { yearId } = this.props;
let url = `/ec_years/${yearId}/ec_training_objectives.json`;
axios.post(url, data).then(res => {
if(res){
message.success('操作成功');
success();
}
}).catch(e => {
console.log(e);
fail(e);
})
}
render() {
let { can_manager } = this.props.year;
let { loading, contentEditState, itemsEditState, objective, editContent, trainingSubitems, validateState, itemValidateState, itemSubmitState, submitState } = this.state;
return (
<div>
<Spin spinning={loading} size='large' style={{ marginTop: '15%' }}>
<div className="educontent ec-training-objective-page">
<div className="ec-head">
<div className="ec-head-left">
<div className="ec-head-label">培养目标</div>
<div className="ec-head-tip">
<span>请结合本专业特色修改培养目标文字描述及目标分解查看详情</span>
<Link to="/forums/3529" target="_blank" className="link ml10">查看详情</Link>
</div>
</div>
<a href={`/api/ec_years/${this.props.yearId}/ec_training_objectives.xlsx`} target="_blank" className="ant-btn ant-btn-primary color-white">导出培养目标</a>
</div>
<Divider/>
<div className="training-objective-body">
{
can_manager && contentEditState ? (
<div className="training-objective-content block">
<div>
<Form.Item label={false} validateStatus={validateState && (!editContent || editContent.length === 0) ? 'error' : ''}>
<Input.TextArea rows={6} value={editContent} onChange={e => this.setState({ editContent: e.target.value })} />
</Form.Item>
</div>
<div className="training-objective-content-form">
<Button type="primary" loading={submitState} onClick={this.saveContentEdit}>保存</Button>
<Button loading={submitState} onClick={this.cancelContentEdit}>取消</Button>
</div>
</div>
) : (
<div className="training-objective-content">
<div className="training-objective-content-text">{ objective.content }</div>
{
can_manager && (
<div className="training-objective-content-edit">
<Tooltip title="编辑">
<Icon type="edit" theme="filled" className="edit-action" onClick={() => this.setState({ contentEditState: true })} />
</Tooltip>
</div>
)
}
</div>
)
}
<div className="training-objective-items">
<div className="training-objective-items-head">
<div className="no-column">分项</div>
<div className="item-content-column">目标分解详情</div>
<div className="operation-column">
{
!can_manager || itemsEditState || (
<Tooltip title="编辑">
<Icon type="edit" theme="filled" className="edit-action" onClick={this.editItemsContent} />
</Tooltip>
)
}
</div>
</div>
<div className="training-objective-items-body">
{
can_manager && itemsEditState ? (
<div>
{
trainingSubitems && trainingSubitems.map((item, index) => {
return (
<div className="training-objective-items-body-item" key={index}>
<div className="no-column">{index + 1}</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={itemValidateState && (!item.content || item.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={item.content} onChange={e => this.onItemContentChange(e, index)} />
</Form.Item>
<div className="item-column-operation">
{ index !== 0 && <Icon type="delete" onClick={() => this.removeItemColumn(index)} /> }
<Icon type="plus-circle" onClick={() => this.addItemColumn(index + 1)} style={{ color: '#29BD8B' }} />
</div>
</div>
</div>
)
})
}
<div className="training-objective-content-form">
<Button type="primary" loading={itemSubmitState} onClick={this.saveItemsContentEdit}>保存</Button>
<Button disabled={itemSubmitState} onClick={this.cancelItemsContentEdit}>取消</Button>
</div>
</div>
) : (
objective.ec_training_items && objective.ec_training_items.map((item, index) => {
return (
<div className="training-objective-items-body-item" key={index}>
<div className="no-column">{ index + 1 }</div>
<div className="item-content-column">{ item.content }</div>
</div>
)
})
)
}
</div>
</div>
</div>
</div>
</Spin>
</div>
)
}
}
TrainingObjective.propTypes = {
schoolId: PropTypes.string,
majorId: PropTypes.string,
yearId: PropTypes.string,
}
export default TrainingObjective

@ -0,0 +1,99 @@
.ec-training-objective-page {
background: #ffffff;
.training-objective {
&-body {
margin-top: -24px;
min-height: 600px;
}
&-content {
display: flex;
padding: 20px 30px;
line-height: 2.0;
&.block {
display: block;
}
&-text {
flex: 1;
}
&-edit {
margin-left: 20px;
& > i {
color: #29BD8B;
cursor: pointer;
font-size: 18px;
}
}
&-form {
margin-top: 10px;
text-align: right;
button {
margin-left: 10px;
}
}
}
&-items {
&-head {
padding: 15px 30px;
display: flex;
background: #F5F5F5;
}
&-body {
margin: 0 30px;
&-item {
display: flex;
min-height: 48px;
padding: 10px 0px;
border-bottom: 1px solid #eaeaea;
&:last-child {
border-bottom: unset;
}
}
}
.no-column {
width: 40px;
text-align: center;
}
.item-content-column {
flex: 1;
padding-left: 10px;
display: flex;
.ant-form-item {
flex: 1;
margin-bottom: 0;
}
.item-column-operation {
display: flex;
justify-content: flex-end;
width: 80px;
& > i {
margin: 15px 10px;
font-size: 18px;
}
}
}
}
}
i.edit-action {
color: #29BD8B;
cursor: pointer;
font-size: 18px;
}
}

@ -0,0 +1,148 @@
import React from 'react';
import { Switch, Route, Link } from 'react-router-dom';
import { Steps, Breadcrumb } from 'antd';
import axios from 'axios';
import './index.scss';
import CustomLoadable from "../../../CustomLoadable";
import Loadable from 'react-loadable';
import Loading from "../../../Loading";
const { Step } = Steps;
const steps = ["培养目标", "毕业要求", "培养目标VS毕业要求", "毕业要求VS通用标准", "学生", "课程体系", "课程体系VS毕业要求", "达成度评价结果"];
const stepTypes = ["training_objectives", "graduation_requirement", "requirement_vs_objective", "requirement_vs_standard", "students", "courses", "requirement_vs_courses", "reach_calculation_info"];
const EcStudentList=Loadable({
loader: () => import('../subroute/ecStudentList/EcStudentList'),
loading: Loading,
});
const Curriculum=Loadable({
loader: () => import('../../../modules/ecs/curriculum/Curriculum'),
loading: Loading,
});
const TrainingObjective=Loadable({
loader: () => import('./TrainingObjective/index'),
loading: Loading,
});
const GraduationRequirement=Loadable({
loader: () => import('./GraduationRequirement/index'),
loading: Loading,
});
const CourseSupports=Loadable({
loader: () => import('./CourseSupports/index'),
loading: Loading,
});
class EcSetting extends React.Component {
constructor (props) {
super(props);
this.state = {
schoolId: null,
majorId: props.match.params.majorId,
yearId: props.match.params.yearId,
year: null,
stepIndex: 0,
}
}
componentDidMount() {
this.setupStep();
this.getYearDetail();
}
getYearDetail = () => {
let { majorId, yearId } = this.state;
axios.get(`/ec_major_schools/${majorId}/ec_years/${yearId}.json`).then(res => {
if(res){
this.setState({ year: res.data, schoolId: res.data.school_id })
}
}).catch(e => console.log(e))
}
onStepChange = (stepIndex) => {
let { majorId, yearId } = this.state;
let type = stepTypes[stepIndex];
this.setState({ stepIndex: stepIndex });
if(type==="courses"){
this.props.history.push(`/ecs/major_schools/${majorId}/years/${yearId}/${type}/ec_course_support_setting/1`);
}else {
this.props.history.push(`/ecs/major_schools/${majorId}/years/${yearId}/${type}`);
}
}
setupStep = () => {
let type = this.props.match.params.type;
let stepIndex = stepTypes.indexOf(type);
this.setState({ stepIndex: stepIndex });
}
render() {
let { year, schoolId, majorId, yearId } = this.state;
let { stepIndex } = this.state;
return (
<div>
<div className="ec-page">
<div className="educontent ec-breadcrumb">
<Breadcrumb separator=">">
<Breadcrumb.Item key="department">
<Link to={`/ecs/department?school_id=${schoolId}`}>{ year && year.school_name }</Link>
</Breadcrumb.Item>
<Breadcrumb.Item key="major-school">
<Link to={`/ecs/major_schools/${majorId}`}>{ year && year.major_name }</Link>
</Breadcrumb.Item>
<Breadcrumb.Item key="year">{year && year.year}</Breadcrumb.Item>
</Breadcrumb>
</div>
<div className="educontent ec-steps">
<Steps type="navigation"
size='small'
className="ec-steps-box"
current={stepIndex}
onChange={this.onStepChange}>
{
steps.map((title, index) => {
return (
<Step subTitle={title} status={index === stepIndex ? 'process' : 'wait'} key={index}/>
)
})
}
</Steps>
</div>
{
year && (
<Switch>
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/training_objectives'
render={ (props) => (<TrainingObjective {...this.props} {...props} {...this.state} />) }></Route>
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/graduation_requirement'
render={ (props) => (<GraduationRequirement {...this.props} {...props} {...this.state} />) }></Route>
{/*学生*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/students'
render={ (props) => (<EcStudentList {...this.props} {...props} {...this.state} />) }></Route>
{/*课程体系*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses'
render={ (props) => (<Curriculum {...this.props} {...props} {...this.state} />) }></Route>
{/*课程体系VS毕业要求*/}
<Route extra path='/ecs/major_schools/:major_school_id/years/:ec_year_id/requirement_vs_courses'
render={ (props) => (<CourseSupports {...this.props} {...props} {...this.state} />) }></Route>
</Switch>
)
}
</div>
</div>
)
}
}
export default EcSetting

@ -0,0 +1,62 @@
.ec-page {
margin-bottom: 50px;
.ec-breadcrumb {
margin-top: 10px;
margin-bottom: 10px;
}
.ec-steps {
&-box {
margin-bottom: 10px;
padding-left: 20px;
padding-right: 20px;
justify-content: space-between;
background: #fff;
.ant-steps-item {
flex: unset !important;
&-container {
margin-left: 0;
}
&.ant-steps-item-active {
.ant-steps-item-subtitle {
color: #1890ff;
}
}
&-subtitle {
margin-left: 0;
margin-right: 8px;
}
}
}
}
.ec-head {
margin-bottom: -24px;
padding: 20px 30px;
display: flex;
align-items: flex-end;
justify-content: space-between;
&-left {
flex: 1;
}
&-label {
font-size: 18px;
}
&-tip {
font-size: 14px;
color: #999999;
}
}
.link {
color: #007bff;
}
}

@ -0,0 +1,108 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, Select, message } from 'antd';
import axios from 'axios';
import './AddYearModal.scss';
const { Option } = Select;
class AddYearModal extends React.Component {
constructor(props) {
super(props);
this.state = {
confirmLoading: false,
error: '',
year: '',
currentYear: new Date().getFullYear()
}
}
handleOk = () => {
let { year } = this.state;
if(!year || year.length === 0){
this.setState({ error: '请选择届别' });
return;
}
this.submitYear();
}
handleCancel = () => {
this.props.onHide(false);
}
onAfterModalClose = () => {
this.setState({ year: '' });
}
submitYear = () => {
let { schoolId, majorId } = this.props;
let { year } = this.state;
this.setState({ confirmLoading: true });
axios.post(`/ec_major_schools/${majorId}/ec_years.json`, { school_id: schoolId, year: year }).then(res => {
if(res.status === 200){
message.success('操作成功');
this.setState({ confirmLoading: false });
this.props.onHide(true);
}
}).catch(e => {
console.log(e);
this.setState({ confirmLoading: false });
})
}
render() {
let { confirmLoading, year, currentYear } = this.state;
return (
<div>
<Modal
title="添加届别"
wrapClassName="add-year-modal"
visible={this.props.visible}
confirmLoading={confirmLoading}
afterClose={this.onAfterModalClose}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div className="add-year-container">
<div className="add-year-tip">
基础数据除学生列表与成绩录入以外的所有基础数据<br/>
将自动复制上届别的数据数据均可再编辑
</div>
<div className="add-year-content">
<div className="add-year-content-label">选择届别</div>
<div className="add-year-content-select">
<Select defaultValue="" value={year} onChange={ value => this.setState({ year: value })} style={{width: '100%'}} placeholder="请选择届别">
{
[...Array(10)].map((_, index) => {
let y = currentYear - 5 + index;
return (
<Option value={ y }>{y}</Option>
)
})
}
</Select>
</div>
</div>
</div>
</Modal>
</div>
)
}
}
AddYearModal.propTypes = {
schoolId: PropTypes.number,
majorId: PropTypes.number,
visible: PropTypes.bool,
onHide: PropTypes.func
}
export default AddYearModal

@ -0,0 +1,34 @@
.add-year-modal {
.add-year {
&-container {
padding: 0 40px;
}
&-tip {
margin-bottom: 20px;
color: #666666;
line-height: 30px;
text-align: center;
}
&-content {
padding: 0 50px;
display: flex;
align-items: center;
&-label {
}
&-select {
flex: 1;
}
}
}
.ant-modal-footer {
padding-bottom: 20px;
text-align: center;
border-top: unset;
}
}

@ -0,0 +1,218 @@
import React from 'react';
import { Link } from 'react-router-dom';
import axios from 'axios';
import { Spin, Button, Table, Input, Divider, Modal, message, Breadcrumb } from 'antd';
import './index.scss';
import AddYearModal from "./AddYearModal";
const { Search } = Input;
const { confirm } = Modal;
const defaultPagination = { current: 1, pageSize: 20, total: 0 };
class EcYear extends React.Component {
constructor (props) {
super(props);
this.state = {
majorId: props.match.params.majorId,
spin: true,
loading: true,
keyword: '',
pagination: {...defaultPagination},
major: {},
yearData: [],
// add year modal vars
addYearModalVisible: false
}
}
componentDidMount() {
this.getMajor();
}
getMajor = () => {
axios.get(`/ec_major_schools/${this.state.majorId}.json`).then(res => {
if(res.status === 200){
window.document.title = res.data.name;
this.setState({ spin: false, major: res.data });
this.getYearData();
}
}).catch(e => console.log(e));
}
onSearch = () => {
this.setState({ pagination: {...defaultPagination} }, () => {
this.getYearData();
})
}
getYearData = () => {
let { majorId, keyword, pagination } = this.state;
axios.get(`/ec_major_schools/${majorId}/ec_years.json`, {
params: {
search: keyword,
page: pagination.current,
per_page: pagination.pageSize
}
}).then(res => {
if(res.status === 200){
let pagination = { ...this.state.pagination };
pagination.total = res.data.count;
this.setState({
loading: false,
yearData: res.data.ec_years,
pagination
})
}
}).catch((e) => {
console.log(e);
this.setState({ loading: false });
})
}
onPaginationChange = (page, pageSize) => {
this.setState({ pagination: { current: page, pageSize: pageSize } }, () => {
this.getYearData()
});
}
showDeleteYearConfirm = (yearId) => {
confirm({
title: '确认删除该届别?',
okText: '确认',
cancelText: '取消',
onOk: () => {
this.deleteYear(yearId);
},
onCancel() {},
});
}
deleteYear = (yearId) => {
let { majorId } = this.state;
axios.delete(`/ec_major_schools/${majorId}/ec_years/${yearId}.json`).then(res => {
if(res.status === 200){
message.success('操作成功');
this.getYearData();
}
}).catch(e => console.log(e))
}
HideAddYearModal = (added) => {
this.setState({ AddYearModalVisible: false });
if(added){
this.setState({ keyword: '', pagination: { ...defaultPagination } }, this.getYearData);
}
}
render() {
let { majorId, spin, keyword, loading, pagination, major, yearData } = this.state;
const linkRender = (num, url) => {
return <Link to={url}>{ num === 0 ? "立即配置" : num }</Link>;
}
const contrastRender = (num, other) => {
let color = other !== 0 && num === other ? 'color-green' : 'color-orange';
return other === 0 ? (
<div className={color}><span>--</span> / <span>--</span></div>
) : (
<div className={color}><span>{num}</span> / <span>{other}</span></div>
)
}
const statusRender = (text, record) => {
let zero = record.graduation_subitem_count === 0;
return zero ? (
<span className="color-orange">--</span>
) : (
<span className={text === 'achieved' ? 'color-green' : 'color-orange'}>
{ text === 'achieved' ? '已达成' : '未达成' }
</span>
)
}
const operationRender = (_, record) => {
return (
<div className="operation-box">
<Link to={`/ecs/major_schools/${majorId}/years/${record.id}/training_objectives`} className="link">立即配置</Link>
<a className="link" onClick={() => this.showDeleteYearConfirm(record.id)}>删除</a>
</div>
)
}
const tableColumns = [
{ title: '届别', dataIndex: 'year', render: text => `${text}` },
{ title: '培养目标', dataIndex: 'training_subitem_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/training_objectives`), },
{ title: '毕业要求', dataIndex: 'graduation_requirement_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/graduation_requirement`), },
{ title: '课程体系', dataIndex: 'course_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/years/${record.id}/ec_course_setting`), },
{ title: '课程目标(达成情况)', key: 'courseTarget', render: (_, record) => { return contrastRender(record.achieved_graduation_course_count, record.course_target_count) } },
{ title: '毕业要求指标点(达成情况)', key: 'graduation', render: (_, record) => { return contrastRender(record.achieved_graduation_objective_count, record.graduation_subitem_count) } },
{ title: '评价结果', dataIndex: 'status', render: statusRender },
{ title: '操作', key: 'operation', render: operationRender }
];
return (
<div className="newMain clearfix">
<Spin size="large" spinning={spin} style={{marginTop: '15%'}}>
<div className="educontent ec-year-list-page">
<div className="educontent ec-breadcrumb">
<Breadcrumb separator=">">
<Breadcrumb.Item key="department">
<Link to={`/ecs/department?school_id=${major && major.school_id}`}>{ major && major.school_name }</Link>
</Breadcrumb.Item>
<Breadcrumb.Item key="major-school">{ major && major.name }</Breadcrumb.Item>
</Breadcrumb>
</div>
<div className="ec-year-list-container">
<div className="year-list-head">
<div className="year-list-head-left">
<div className="year-list-head-label">{ major.name }</div>
<div className="year-list-head-tip">
<span>请选择添加参与认证的学生界别多个界别分次添加</span>
<Link to="/forums/3528" target="_blank" className="link ml10">查看详情</Link>
</div>
</div>
<Button type="primary" onClick={() => this.setState({ AddYearModalVisible: true })}>添加届别</Button>
</div>
<Divider/>
<div className="year-list-body">
<div className="year-list-search">
<Search
placeholder="届别检索"
onInput={e => this.setState({keyword: e.target.value})}
onSearch={this.onSearch}
value={keyword}
style={{ width: 200 }}/>
</div>
<div className="year-list-table">
<Table rowKey="id"
loading={loading}
columns={tableColumns}
dataSource={yearData}
pagination={{...pagination, onChange: this.onPaginationChange}}/>
</div>
</div>
</div>
</div>
<AddYearModal schoolId={major && major.school_id}
majorId={majorId}
visible={this.state.AddYearModalVisible}
onHide={this.HideAddYearModal}/>
</Spin>
</div>
)
}
}
export default EcYear;

@ -0,0 +1,62 @@
.ec-year-list-page {
.ec-breadcrumb {
margin-top: 10px;
margin-bottom: 10px;
}
.ec-year-list-container {
background: #fff;
}
.year-list {
&-head {
margin-bottom: -24px;
padding: 20px 30px;
display: flex;
align-items: flex-end;
justify-content: space-between;
&-left {
flex: 1;
}
&-label {
font-size: 18px;
}
&-tip {
font-size: 14px;
color: #999999;
}
}
&-body {
margin-top: -24px;
}
&-search {
padding: 20px 30px;
display: flex;
flex-direction: row-reverse;
}
&-table {
min-height: 400px;
th, td {
text-align: center;
}
}
}
.link {
color: #007bff;
}
.operation-box {
.link {
margin: 0 5px;
}
}
}

@ -0,0 +1,27 @@
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { SnackbarHOC } from 'educoder';
import CustomLoadable from "../../CustomLoadable";
import {TPMIndexHOC} from "../tpm/TPMIndexHOC";
const Home = CustomLoadable(() => import('./Home/index'));
const EcYear = CustomLoadable(() => import('./EcYear/index'));
const EcSetting = CustomLoadable(() => import('./EcSetting/index'));
class Ecs extends React.Component {
render() {
return (
<div className="newMain clearfix">
<Switch>
<Route extra path='/ecs/department' component={Home}></Route>
<Route path='/ecs/major_schools/:majorId/years/:yearId/:type' component={EcSetting}></Route>
<Route extra path='/ecs/major_schools/:majorId' component={EcYear}></Route>
</Switch>
</div>
)
}
}
export default SnackbarHOC() (TPMIndexHOC ( Ecs ));

@ -0,0 +1,179 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, Input, Table, message } from 'antd';
import axios from 'axios';
import './AddMajorModal.scss';
const { Search } = Input;
const tableColumns = [
{ title: '专业代码', dataIndex: 'code', key: 'code', width: 100, },
{ title: '专业名称', dataIndex: 'name', key: 'name', },
{ title: '', dataIndex: 'selected', key: 'selected', width: 80, render: selected => selected && <span className="color-orange">已选择</span> },
];
const defaultPagination = { current: 1, pageSize: 10, total: 0 };
class AddMajorModal extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
confirmLoading: false,
error: '',
keyword: '',
pagination: {...defaultPagination},
schoolId: props.schoolId,
majorData: [],
selectedData: []
}
this.getMajors = this.getMajors.bind(this);
this.selectMajor = this.selectMajor.bind(this);
this.onAfterModalClose = this.onAfterModalClose.bind(this);
this.handleOk = this.handleOk.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.onPaginationChange = this.onPaginationChange.bind(this);
}
componentDidUpdate(prevProps) {
if(!prevProps.visible && this.props.visible){
this.getMajors();
}
}
onSearch = () => {
this.setState({ pagination: {...defaultPagination} }, () => {
this.getMajors();
})
}
getMajors(){
let { schoolId, keyword, pagination } = this.state;
this.setState({ loading: true });
axios.get(`/schools/${schoolId}/ec_majors.json`, {
params: {
search: keyword,
page: pagination.current,
per_page: pagination.pageSize
}
}).then(res => {
if(res.status === 200){
let pagination = { ...this.state.pagination };
pagination.total = res.data.count;
this.setState({
majorData: res.data.ec_majors,
loading: false,
pagination,
})
}
}).catch(e => {
console.log(e);
this.setState({ loading: false })
})
}
getCheckboxProps(record){
return { ...record, disabled: record.selected }
}
selectMajor(selectedRowKeys){
this.setState({ selectedData: selectedRowKeys });
}
onPaginationChange(page, pageSize){
this.setState({ pagination: { current: page, pageSize: pageSize } }, () => {
this.getMajors()
});
}
handleOk(){
let { selectedData } = this.state;
if(selectedData.length === 0){
this.setState({ error: '请选择专业' });
return;
}
this.submitMajor(selectedData);
}
handleCancel(){
this.props.onHide(false);
}
onAfterModalClose(){
this.setState({
error: '',
keyword: '',
pagination: {...defaultPagination},
majorData: [],
selectedData: [],
});
}
submitMajor(ids) {
let { schoolId } = this.state;
this.setState({ confirmLoading: true });
axios.post(`/schools/${schoolId}/ec_major_schools.json`, { major_ids: ids }).then(res => {
if(res.status === 200){
message.success('操作成功');
this.setState({ confirmLoading: false });
this.props.onHide(true);
}
}).catch(e => {
console.log(e);
this.setState({ confirmLoading: false });
})
}
render() {
let { loading, keyword, majorData, selectedData, pagination } = this.state;
return (
<div>
<Modal
title="添加认证专业"
wrapClassName="add-major-modal"
visible={this.props.visible}
confirmLoading={this.state.confirmLoading}
afterClose={this.onAfterModalClose}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div className="add-major-search">
<Search
placeholder="专业代码/专业名称检索"
onInput={e => this.setState({keyword: e.target.value})}
onSearch={this.onSearch}
value={keyword}/>
</div>
<div className="add-major-body">
<Table rowKey="id"
rowSelection={{onChange: this.selectMajor, getCheckboxProps: this.getCheckboxProps, selectedRowKeys: selectedData}}
loading={loading}
columns={tableColumns}
dataSource={majorData}
pagination={{...pagination, onChange: this.onPaginationChange}}
size="small"
scroll={{ y: 200 }}/>
<div className="error">{ this.state.error }</div>
</div>
</Modal>
</div>
)
}
}
AddMajorModal.propTypes = {
schoolId: PropTypes.number,
visible: PropTypes.bool,
onHide: PropTypes.func
}
export default AddMajorModal

@ -0,0 +1,29 @@
.add-major-modal {
.add-major-search {
margin-bottom: 20px;
}
.ant-modal-body {
padding-bottom: 0;
.major-row {
padding: 10px;
}
.ant-table-thead {
background: #fafafa;
}
.ant-table-scroll {
min-height: 250px;
}
.error {
height: 20px;
margin-top: -20px;
color: red;
}
}
.ant-modal-footer {
padding-bottom: 20px;
text-align: center;
border-top: unset;
}
}

@ -0,0 +1,226 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, Input, Table, message, Select, Form, Row, Col, Button } from 'antd';
import axios from 'axios';
import './AddManagerModal.scss';
const { Option } = Select;
const columnRender = (text) => <div style={{ wordWrap: 'break-word', wordBreak: 'break-all' }}> {text} </div>
const tableColumns = [
{ title: '姓名', dataIndex: 'name', key: 'name', width: 60, render: columnRender },
{ title: '职称', dataIndex: 'identity', key: 'identity', width: 60, },
{ title: '单位', dataIndex: 'school_name', key: 'school_name', render: (_, record) => columnRender(`${record.school_name} ${record.department_name}`) },
{ title: '手机号', dataIndex: 'phone', key: 'phone', width: 80, },
];
const defaultPagination = { current: 1, pageSize: 20, total: 0 };
class AddManagerModal extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
confirmLoading: false,
nameValidateStatus: '',
error: '',
name: '',
school: props.schoolName,
identity: '',
pagination: {...defaultPagination},
schoolId: props.schoolId,
userData: [],
selectedData: []
}
this.getUsers = this.getUsers.bind(this);
this.selectUser = this.selectUser.bind(this);
this.onAfterModalClose = this.onAfterModalClose.bind(this);
this.handleOk = this.handleOk.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.onPaginationChange = this.onPaginationChange.bind(this);
}
onSearch = () => {
this.setState({ pagination: {...defaultPagination} }, () => {
this.getUsers();
})
}
getUsers(){
let { majorId } = this.props;
let { name, school, identity, pagination } = this.state;
if(name.length === 0){
this.setState({ nameValidateStatus: 'error' });
return;
}
this.setState({ loading: true });
axios.get(`/ec_major_schools/${majorId}/users.json`, {
params: {
name, school, identity,
page: pagination.current,
per_page: pagination.pageSize
}
}).then(res => {
if(res.status === 200){
let pagination = { ...this.state.pagination };
pagination.total = res.data.count;
this.setState({
userData: res.data.users,
loading: false,
pagination,
})
}
}).catch(e => {
console.log(e);
this.setState({ loading: false })
})
}
getCheckboxProps(record){
return { ...record, disabled: record.manager }
}
selectUser(selectedRowKeys){
this.setState({ selectedData: selectedRowKeys });
}
onPaginationChange(page, pageSize){
this.setState({ pagination: { current: page, pageSize: pageSize } }, () => {
this.getUsers()
});
}
onNameChange = (e) => {
let name = e.target.value;
let nameValidateStatus = '';
if(name.length === 0){
nameValidateStatus = 'error'
}
this.setState({ nameValidateStatus, name });
}
handleOk(){
this.setState({ error: '' });
let { selectedData } = this.state;
if(selectedData.length === 0){
this.setState({ error: '请选择至少一个用户' });
return;
}
this.submitUsers(selectedData);
}
handleCancel(){
this.props.onHide(false);
}
onAfterModalClose(){
this.setState({
error: '',
nameValidateStatus: '',
name: '',
school: this.props.schoolName,
identity: '',
pagination: {...defaultPagination},
userData: [],
selectedData: [],
});
}
submitUsers(ids) {
let { majorId } = this.props;
this.setState({ confirmLoading: true });
axios.post(`/ec_major_schools/${majorId}/major_managers.json`, { user_ids: ids }).then(res => {
if(res.status !== 200){ return }
message.success('操作成功');
this.setState({ confirmLoading: false });
this.props.onHide(true);
}).catch(e => {
console.log(e);
this.setState({ confirmLoading: false });
})
}
render() {
let { loading, name, school, identity, userData, selectedData, pagination, nameValidateStatus } = this.state;
return (
<div>
<Modal
title="添加管理员"
wrapClassName="add-ec-manager-modal"
visible={this.props.visible}
confirmLoading={this.state.confirmLoading}
afterClose={this.onAfterModalClose}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div className="add-ec-manager-search">
<Form layout="horizontal">
<Row>
<Col span={12}>
<Form.Item label="姓名" labelCol={{ span: 6 }} wrapperCol={{span: 16}} validateStatus={nameValidateStatus}>
<Input onChange={this.onNameChange} value={name} placeholder="请输入姓名" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="职业" labelCol={{ span: 6 }} wrapperCol={{span: 17}} >
<Select value={identity} onChange={value => this.setState({ identity: value }) } placeholder="请选择职业">
<Option value="">全部</Option>
<Option value="teacher">教师</Option>
<Option value="student">学生</Option>
<Option value="professional">专业人士</Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={18}>
<Form.Item label="学校" labelCol={{ span: 4 }} wrapperCol={{span: 18}}>
<Input onChange={e => this.setState({ school: e.target.value })} value={school} placeholder="请输入学校名称"/>
</Form.Item>
</Col>
<Col span={4} offset={2}>
<Button type="primary" className="mt5" onClick={this.onSearch}>搜索</Button>
</Col>
</Row>
</Form>
</div>
<div className="add-ec-manager-body">
<Table rowKey="id"
rowSelection={{onChange: this.selectUser, getCheckboxProps: this.getCheckboxProps, selectedRowKeys: selectedData, columnWidth: 40}}
loading={loading}
columns={tableColumns}
dataSource={userData}
pagination={{...pagination, onChange: this.onPaginationChange}}
size="small"
scroll={{ y: 200 }}/>
<div className="error">{ this.state.error }</div>
</div>
</Modal>
</div>
)
}
}
AddManagerModal.propTypes = {
schoolId: PropTypes.string,
schoolName: PropTypes.string,
majorId: PropTypes.number,
visible: PropTypes.bool,
onHide: PropTypes.func
}
export default AddManagerModal

@ -0,0 +1,35 @@
.add-ec-manager-modal {
.ant-modal-body {
padding-bottom: 0;
.ant-table-thead {
background: #fafafa;
}
.ant-table-scroll {
min-height: 250px;
}
.add-ec-manager-search {
margin-bottom: 20px;
.ant-form-item {
margin-bottom: 0;
&-label > label {
font-size: 14px !important;
}
}
}
.error {
height: 20px;
margin-top: -20px;
color: red;
}
}
.ant-modal-footer {
padding-bottom: 20px;
text-align: center;
border-top: unset;
}
}

@ -0,0 +1,60 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tag, message } from 'antd';
import axios from 'axios';
class MajorManager extends React.Component {
constructor(props) {
super(props);
this.state = {
schoolId: props.schoolId,
majorId: props.majorId,
canManage: props.canManage,
managers: props.managers
}
this.deleteManager = this.deleteManager.bind(this);
}
componentDidUpdate(prevProps) {
if(this.props.managers.length !== prevProps.managers.length){
this.setState({ managers: this.props.managers });
}
}
deleteManager(managerId){
axios.delete(`/ec_major_schools/${this.state.majorId}/major_managers/${managerId}.json`).then(result => {
if(result.status === 200){
message.success('操作成功');
}
}).catch(e => { console.log(e) })
}
render() {
let { canManage, managers } = this.state;
return (
<div className="manager-box-content">
{
managers && managers.map(manager => {
return (
<Tag key={manager.id} closable={canManage} onClose={() => { this.deleteManager(manager.id) }} color="blue">
{ manager.name }
</Tag>
)
})
}
</div>
)
}
}
MajorManager.propTypes = {
schoolId: PropTypes.string,
majorId: PropTypes.number,
canManage: PropTypes.bool,
managers: PropTypes.array
}
export default MajorManager

@ -0,0 +1,265 @@
import React from 'react';
import { Link } from 'react-router-dom';
import { Spin, Avatar, Tooltip, Button, Divider, Input, Row, Col, Icon, Modal } from "antd";
import { getImageUrl } from 'educoder';
import axios from 'axios';
import './index.scss';
import bgImage from '../../../images/ecs/bg.jpg';
import MajorManager from "./MajorManager";
import AddMajorModal from "./AddMajorModal";
import AddManagerModal from "./AddManagerModal";
const { Search } = Input;
const { confirm } = Modal;
class Home extends React.Component {
constructor (props) {
super(props);
const searchParams = new URLSearchParams(props.location.search.substring(1));
let schoolId = searchParams.get('school_id');
if(!schoolId){
this.props.history.push(`/nopage`);
return;
}
this.state = {
loading: true,
majorLoading: true,
AddMajorVisible: false,
AddManagerVisible: false,
searchKeyword: '',
schoolId: schoolId,
currentMajorId: null,
school: null,
currentUser: null,
managers: null,
templateMajor: null,
majors: null,
majorCount: 0
}
this.getSchoolMajors = this.getSchoolMajors.bind(this);
this.HideAddMajorModal = this.HideAddMajorModal.bind(this);
this.showDeleteMajorConfirm = this.showDeleteMajorConfirm.bind(this);
this.showAddManagerModal = this.showAddManagerModal.bind(this);
this.HideAddManagerModal = this.HideAddManagerModal.bind(this);
}
componentDidMount() {
this.getSchoolDetail();
}
getSchoolDetail() {
axios.get(`/schools/${this.state.schoolId}/detail.json`).then(result => {
if(result.status === 200){
window.document.title = result.data.school.name;
this.setState({
school: result.data.school,
currentUser: result.data.current_user,
managers: result.data.school_managers,
loading: false
});
this.getSchoolMajors();
}
}).catch(e => {
console.log(e);
this.setState({ loading: false });
});
}
getSchoolMajors(){
let that = this;
let keyword = this.state.searchKeyword;
this.setState({ majorLoading: true });
axios.get(`/schools/${this.state.schoolId}/ec_major_schools.json?search=${keyword}&per_page=50`).then(result => {
if(result.status === 200){
that.setState({
majorCount: result.data.count,
templateMajor: result.data.template_ec_major_school,
majors: result.data.ec_major_schools,
majorLoading: false
});
}
}).catch(e => {
console.log(e);
that.setState({ majorLoading: false });
});
}
showAddManagerModal(majorId){
this.setState({ currentMajorId: majorId, AddManagerVisible: true });
}
HideAddMajorModal(added){
this.setState({ AddMajorVisible: false });
if(added){
this.setState({ searchKeyword: '' }, this.getSchoolMajors)
}
}
HideAddManagerModal(added){
this.setState({ AddManagerVisible: false });
if(added){
this.setState({ searchKeyword: '' }, this.getSchoolMajors)
}
}
showDeleteMajorConfirm(majorId){
confirm({
title: '确认删除该认证专业?',
okText: '确认',
cancelText: '取消',
onOk: () => {
this.deleteMajor(majorId);
},
onCancel() {},
});
}
deleteMajor(majorId){
let { schoolId, majorCount, majors } = this.state;
axios.delete(`/schools/${schoolId}/ec_major_schools/${majorId}.json`).then(res => {
if(res.status === 200){
this.setState({
majorCount: majorCount - 1,
majors: majors.filter(major => major.id !== majorId)
});
}
}).catch(e => console.log(e))
}
render() {
let { currentUser, school, managers, templateMajor, majors, majorCount } = this.state;
const manageSchool = !!currentUser && (currentUser.manager || currentUser.admin);
const manageMajor = !!currentUser && (manageSchool || currentUser.major_manager);
const configBtnText = manageMajor ? '配置' : '查看';
return (
<div className="newMain clearfix">
<Spin spinning={this.state.loading} size="large" style={{marginTop:'15%'}}>
<div className="ec-home">
<div className="pr mb20">
<div className="head-image" style={{background: `url(${bgImage}) no-repeat top center`}}>
<span className="font-30 color-white font-bd">{ school && school.name }</span>
</div>
</div>
<div className="educontent mb20 ec-home-item school-manager-item">
<div className="ec-home-item-head">
<div className="ec-home-item-label">学校管理员</div>
<div className="ec-home-item-tip">温馨提醒学校管理员有添加专业及设置专业管理员等权限</div>
</div>
<div className="ec-home-item-body ec-school-manager">
{
managers && managers.map((manager) => {
return (
<Link to={`/users/${manager.login}`} key={manager.id} className="ec-school-manager-item">
<Avatar size={48} src={getImageUrl(`images/${manager.image_url}`)} alt="头像"/>
<Tooltip title={manager.name} placement="bottom">
<span className="ec-school-manager-name">{ manager.name }</span>
</Tooltip>
</Link>
)
})
}
</div>
</div>
<div className="educontent mb50 ec-home-item major-list-item">
<div className="ec-home-item-head">
<div className="major-list-item-head">
<div className="ec-home-item-label">专业列表</div>
<div className="ec-home-item-tip">
<span>请添加参与认证的专业名称</span>
<Link to="/forums/3527" target="_blank" className="link ml10">查看详情</Link>
</div>
</div>
<Button type="primary" onClick={() => { this.setState({ AddMajorVisible: true }) }}>添加专业</Button>
</div>
<Divider/>
<div className="major-list-container">
<div className="major-list-head">
<div className="total">{majorCount || 0} 个检索结果{majorCount || 0} 专业</div>
<Search
placeholder="专业代码/专业名称检索"
onInput={e => this.setState({searchKeyword: e.target.value})}
onSearch={this.getSchoolMajors}
value={this.state.searchKeyword}
style={{ width: 200 }}
/>
</div>
<div className="major-list-body">
<Row className="major-list-row head">
<Col span={2} className="textcenter">序号</Col>
<Col span={4}>专业代码</Col>
<Col span={6}>专业名称</Col>
<Col span={8}>专业管理员</Col>
<Col span={4} className="textcenter">操作</Col>
</Row>
<Spin spinning={this.state.majorLoading}>
{
templateMajor && (
<Row className="major-list-row">
<Col span={2} className="textcenter">0</Col>
<Col span={4}>000000</Col>
<Col span={6}>
<Link to={`/ecs/major_schools/${templateMajor.id}`}>{ templateMajor.name }</Link>
</Col>
<Col span={8}></Col>
<Col span={4} className="textcenter">
<Link to={`/ecs/major_schools/${templateMajor.id}`} className="link">{ configBtnText }</Link>
</Col>
</Row>
)
}
{
majors && majors.map((major, index) => {
return (
<Row className="major-list-row" key={major.id}>
<Col span={2} className="textcenter">{ index + 1 }</Col>
<Col span={4}>{ major.code }</Col>
<Col span={6}>
<Link to={`/ecs/major_schools/${major.id}`}>{ major.name }</Link>
</Col>
<Col span={8}>
<div className="manager-box">
{ manageMajor && <a className="link mr10" onClick={() => this.showAddManagerModal(major.id)}><Icon type="plus-circle" /></a> }
<MajorManager schoolId={school.id}
majorId={major.id}
canManage={manageMajor}
managers={major.major_managers}></MajorManager>
</div>
</Col>
<Col span={4} className="textcenter operate-box">
<Link to={`/ecs/major_schools/${major.id}`} className="link">{ configBtnText }</Link>
{ manageSchool && ( <a className="link" onClick={() => this.showDeleteMajorConfirm(major.id)}>删除</a> ) }
</Col>
</Row>
)
})
}
</Spin>
</div>
</div>
</div>
</div>
<AddMajorModal schoolId={this.state.schoolId} visible={this.state.AddMajorVisible} onHide={this.HideAddMajorModal}/>
{ this.state.school && <AddManagerModal schoolId={this.state.schoolId} schoolName={this.state.school.name} majorId={this.state.currentMajorId} visible={this.state.AddManagerVisible} onHide={this.HideAddManagerModal}/> }
</Spin>
</div>
)
}
}
export default Home;

@ -0,0 +1,127 @@
.ec-home {
.head-image {
width: 100%;
height: 240px;
background-size: 100% 100%;
justify-content: center;
align-items: center;
display: -webkit-flex;
}
.ec-home-item {
background: #fff;
&-head {
display: flex;
align-items: baseline;
margin-bottom: 20px;
}
&-label {
margin-right: 20px;
font-size: 18px;
}
&-tip {
color: #999;
font-size: 12px;
}
&.major-list-item {
.ec-home-item {
&-head {
margin-bottom: -24px;
padding: 20px 30px;
justify-content: space-between;
align-items: center;
}
&-tip {
font-size: 14px;
}
}
}
}
.school-manager-item {
padding: 20px 30px;
}
.ec-school-manager {
display: flex;
flex-wrap: wrap;
&-item {
margin-right: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
&-name {
display: block;
text-align: center;
max-width: 48px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
color: #666;
}
}
.major-list-item {
.major-list {
&-container {
}
&-head {
margin-top: -24px;
padding: 20px 30px;
display: flex;
align-items: center;
justify-content: space-between;
.total { font-size: 12px; }
}
&-body {
padding-bottom: 30px;
}
&-row {
padding: 10px 15px;
border-bottom: 1px solid #eee;
&:last-child { border-bottom: unset; }
&.head {
background: #F5F5F5;
}
.ant-btn-link {
text-align: center;
}
}
}
}
.operate-box {
.link {
margin: 0 5px;
}
}
.manager-box {
display: flex;
align-items: center;
&-content {
flex: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
}
}
.link {
color: #007bff;
}
}

@ -0,0 +1,27 @@
.newedu-class-container{
width:1240px;
height:84px;
}
.ecnewbutton{
width:68px;
height:30px;
background:rgba(76,172,255,1);
border-radius:2px;
float:right;
}
.newedu-title-bottom{
width:1240px;
height:65px;
}
.edu-con-bottom {
padding: 10px 0;
background: #fff;
font-size: 16px;
}
.TabledataSource .ant-table-wrapper{
width: 1240px;
}
.ant-table-thead{
background:rgba(245,245,245,1);
}

@ -0,0 +1,576 @@
.TrainingLecturer{
font-size:18px;
font-family:MicrosoftYaHei;
font-weight:400;
color:#656565;
}
.TrainingTheory{
font-size:18px;
font-family:MicrosoftYaHei;
font-weight:400;
color:#05101A !important;
}
#SystemParameters{
height: 81px;
line-height: 40px;
}
#SystemParameters .SystemParameters:nth-child(1){
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
/* color:#989898 !important; */
}
#SystemParameters .SystemParameters:nth-child(2){
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
color:#989898 !important;
}
.operationright{
float:right !important;
}
.ml75{
margin-left:75px;
}
.mlim30{
margin-left:30px !important;
}
.RadioGroupbox{
display: inline-block;
width: 100px;
height: 25px;
position: relative;
}
.RadioGroupboxab{
position: absolute;
top: -5px;
left: 30px;
}
.buttoninline{
display: inline-block;
margin-left: 29px;
position: relative;
/* width: 100px; */
margin-top: 0px;
height: 25px;
}
.placeholder::-moz-placeholder{font-size:12px;}
.placeholder::-webkit-input-placeholder{font-size:12px;}
.placeholder:-ms-input-placeholder{font-size:12px;}
.mr16{
margin-right:16px;
}
.defalutSubmitbtn{
cursor: pointer;
}
.defalutCancelbtn{
cursor: pointer;
}
.newSystem{
background: #fff;
}
/* #EvaluationsList{
padding:20px 0px;
} */
.mt55{
margin-top:55px !important;
}
.mb100{
margin-bottom:100px !important;
}
.mt26{
margin-top:26px !important;
}
.mb80{
margin-bottom:80px !important;
}
.color99{
color:#999999;
}
.ant-select-selection__placeholder{
width: 100%;
font-size:14px;
height:58px;
}
.mt70{
margin-top:70px;
}
.mb50{
margin-bottom:50px;
}
/* 谷歌 */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
font-size:14px;
}
/* 火狐 */
input{
-moz-appearance:textfield;
font-size:14px;
}
.ColorF68{
color:#FF6800;
}
.eaSystemp a{
color:#05101a;
}
.eaSystemp span{
color: #05101a !important;
}
.editorModify div .ant-input-lg{
font-size: 14px;
}
#Coursemultiple div div ul .ant-select-selection__choice{
margin-left: 0px;
height: 20px !important;
min-height: 29px;
font-size: 14px;
line-height: 27px;
margin-top: 4px;
margin-bottom: 3px;
}
#Coursemultiple .ant-select-selection--multiple{
min-height: 40px !important;
line-height: 38px !important;
}
#Coursemultiple div div ul .ant-select-search.ant-select-search--inline{
margin-left: 0px;
height: 20px !important;
min-height: 29px;
font-size: 14px;
line-height: 27px;
margin-top: 4px;
margin-bottom: 3px;
}
.neweditSubentry{
position: relative;
top: -4px;
left: 7px;
}
.nulleditSubentry{
position: relative;
top: -4px;
left: 3px;
}
.percentage{
margin-left: 8px;
padding-left: 25px !important;
}
.Coursetitle{
margin-bottom:0px !important;
}
.textaligncenter{
padding-left: 30px !important;
width: 70px !important;
}
.ml72{
margin-left:72px;
}
.bordereaeaea{
border-bottom: 1px solid transparent !important;
}
.ecnowrap{
max-width: 170px;
display: inline-block;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
color: #40a9ff !important;
margin-right: 108px;
}
.ecblock{
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.Spinlarge{
text-align: center;
width: 100%;
margin-top: 25px;
margin-bottom: 25px;
}
/* .ant-select-search{
display:none;
}
.ant-select-search--inline{
display:none;
} */
.boxinline-block{
display: inline-block;
}
.boxinline{
margin-right: 20px;
}
.evaluationdataClass{
margin-left: 217px !important;
width: 589px !important;
display: inline-block;
}
.absolute{
position:absolute;
}
.ml115{
margin-left: 115px;
}
.ml100{
margin-left: 100px;
}
.Importclassroomdata{
position: absolute;
right: 18px;
top: 26px;
}
.Importclassroomdatas{
position: absolute;
right: 375px!important;
top: 122px !important;
}
.Importclassroomdatass {
position: absolute;
right: 375px !important;
top: 248px !important;
}
#SystemParameters{
position: relative;
}
.newSystem .newtarget_scoreclass{
padding: 10px 0px !important;
margin: 0px 20px !important;
}
.newSystem .newtarget_target{
padding: 10px 0px !important;
margin: 0px 30px !important;
border-bottom:1px solid transparent !important;
}
.nowrap329{
max-width: 329px !important;
text-align: left;
overflow:hidden;
text-overflow:ellipsis;
white-space:nowrap;
color:transparent !important;
min-width: 329px !important;
}
.ListTableLine li>.column-500{
max-width: 360px !important;
text-align: left;
min-width: 360px !important;
}
.color-666{
color:#666666 !important;
}
.color-05101A{
color:#05101A !important;
}
#SystemParametersP{
position:relative;
margin-bottom:0px !important;
}
.major_name{
cursor:inherit;
}
.padding1030{
padding: 10px 30px;
height: 60px !important;
}
.color-red{
color:#DD1717;
}
.color-redFF{
color:#FF6666;
}
.margin-left63{
margin-left: 63px !important;
}
.colorTransparent{
color:transparent !important;
}
.color999{
color: #999999 !important;
}
.operationrightbotton{
margin-top: 2px!important;
margin-right: -25px;
}
.mr2{
margin-right:2px;
}
.colorFF6800{
color: #FF6800 !important;
}
.lineheight60{
line-height: 52px !important;
}
.mr13{
margin-right: 13px;
}
.mr14{
margin-right: 14px;
}
.ecmorelist{
margin: 0 auto;
width: 100px;
/* height: 100px; */
display: block;
}
.padding10im{
padding: 10px 0px !important;
}
.lipadding10im{
margin: 0 0px!important;
}
.lipadding20im{
padding: 10px 20px!important;
}
.marlr19{
margin: 0 19px!important;
}
.mrj15{
margin-right: -15px;
}
.margin64px{
margin: 0 64px!important;
}
.marginright84{
margin-right: 84px!important;
}
.marginright162{
margin-right: 162px;
}
.width86{
width: 86px!important;
}
.ant-modal-mask {
background-color: rgba(5,16,26,0.4);
}
.ecmodeldelet{
/* 考虑有各种尺寸的屏幕,用比例 */
top:36%;
}
.ecmodeldelet .ant-modal-header{
padding: 0px 24px;
}
.ecmodeldelet .ant-modal-title{
padding: 0px 15px;
text-align: center;
box-sizing: border-box;
line-height: 70px;
height: 70px;
border-radius: 10px 10px 0px 0px;
font-size: 16px;
font-weight: bold;
}
a.TrainingLecturer:hover{
color:#4CACFF !important;
}
.newSystem .lipadding10im{
margin: 0 0px!important;
}
.operationleft{
float:left !important;
}
.color4D4D4D{
color:#4D4D4D !important;
}
/* #SystemParameters .SystemParameters:nth-child(1){
color:#4D4D4D !important;
} */
.color4CACFF{
color:#4CACFF !important;
}
.SystemParameters4CACFF{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
line-height: 45px;
}
.detaillist{
text-align: center !important;
width: 133px !important;
height: 24px ;
}
.associatedclass{
margin-right: 128px !important;
}
.associatedclasslist{
width: 234px;
height: 20px;
font-size: 14px;
font-family: MicrosoftYaHei;
font-weight: 400;
color: rgba(101,101,101,1);
line-height: 22px;
margin: 6px auto;
}
.associatedclasslists{
width: 323px;
height: 35px;
font-size: 14px;
font-family: MicrosoftYaHei;
font-weight: 400;
color: rgba(101,101,101,1);
line-height: 22px;
margin: 6px auto;
margin-bottom: 15px;
}
.newecmodeldelet{
width:600px !important;
top:100px;
}
.assclasslistsearch{
width:454px;
height:36px;
background:rgba(244,244,244,1);
border:1px solid rgba(234,234,234,1);
border-radius:4px;
position: relative;
}
.assclassposition{
position: absolute;
top: 3px;
left: 9px;
}
.assclasslistsearchbtn{
width: 64px;
height: 35px !important;
font-weight: 300 !important;
line-height: 35px !important;
}
.btnweight{
font-weight: 300 !important;
color: #fff !important;
}
.CBCBCB{
background:#CBCBCB!important;
}
.clear{
clear: both;
}
.ml120{
margin-left: 120px;
}
.ml88{
margin-left: 88px;
}
.assclasslistmid{
width: 540px;
height: 282px;
background: rgba(244,250,255,1);
border-radius: 4px;
margin-left: 10px;
overflow: auto;
padding-top: 10px;
}
.assclasslistsubmit{
margin-top: 26px !important;
margin-bottom: 8px !important;
}
.ant-modal-header{
border-top-left-radius:10px;
border-top-right-radius:10px;
}
.ant-modal-content{
border-radius: 10px;
}
.assclasslistmidname{
width: 160px;
overflow: hidden;
/* height: 24px; */
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bordereaeaeas{
border-bottom: 1px solid #eaeaea !important;
}
.isreloadsbtn{
width: 80px !important;
font-weight: 400 !important;
padding: 0px !important;
padding-left: 10px !important;
}
.f5f5f5{
color:rgb(245, 245, 245) !important;
}
.ant-select-selection{
border-radius: 0px !important;
background-color: #F5F5F5;
}
.ant-select-selection:focus{
border-radius: 0px !important;
background-color: #fff;
border-color: #d9d9d9 !important;
}
.listchildbox{
overflow: hidden;
}
.listchildboxs{
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ant-input:focus, .ant-input:hover{
border-color: transparent;
}
.inputWeight{
background-color: #F5F5F5;
}
.inputWeight:focus {
background-color: #fff;
}
.ant-input:focus {
outline: 0;
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-input{
border-color: #d9d9d9 !important;
}
.mt60{
margin-top:60px;
}
.SystemParameters{
height:auto;
}

@ -0,0 +1,368 @@
.eaSystemp a{
color:#05101a;
}
.eaSystemp span{
color: #05101a !important;
}
.eacourse p{
height:84px;
margin-bottom:0px !important;
}
.eacourse #training_objective_contents{
height:81px;
}
.courseSystem{
font-size:18px;
font-family:MicrosoftYaHei;
font-weight:400;
line-height:45px;
color:rgba(5,16,26,1);
}
.SystemParameters{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
line-height:45px;
color:rgba(50,50,50,1);
}
.SystemParametersysls{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
color:rgba(50,50,50,1);
}
.Systemnum{
font-size:14px;
font-family:MicrosoftYaHei;
font-weight:400;
color:#FF6800;
}
.newSystem{
width:1200px;
overflow:auto;
background: #FFF;
}
.newSystem .clearfix .column-1{
width: 113px !important;
text-align: center;
}
.operationColumn{
margin: 0px 10%;
width:100%;
height:100%;
}
.operationalter{
margin: 20px 16px;
}
.SystemModifythelist .column-1{
width: 120px !important;
text-align: center;
}
.SystemModifythelist .column-3{
padding-left: 96px;
margin-right: 23px;
}
.operationright{
float:right !important;
}
.newSystem p{
/*padding: 10px 33px !important;*/
margin-bottom: 0em;
}
.newSystem li{
margin:0 !important;
}
.SystemModifythelist{
background:#FFF !important;
}
.SystemModifythelist .column-1:nth-child(1){
margin-left: 7px;
}
.Systempoint{
font-size:12px;
font-family:MicrosoftYaHei;
font-weight:400;
color:rgba(152,152,152,1);
}
.editorModify{
background:#FFF !important;
}
.newSystem .editorModify .column-1{
width: 194px !important;
text-align: left;
margin-left: 30px;
}
.newSystem .editorModify .column-1:nth-child(1){
margin-right: 510px;
}
.editorModify .ant-select{
width: 556px !important;
margin-left: 36px;
}
.editorModify .ant-select .ant-select-selection{
height: 30px !important;
}
.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered{
height: 30px !important;
}
.editorModify .ant-select .ant-select-selection .ant-select-selection__rendered .ant-select-selection-selected-value{
line-height: 30px !important;
}
.inputWeight{
width: 20%;
font-size:14px;
height:30px;
margin-left: 20px;
background-color: #F5F5F5;
}
.SetTheAssociated{
width: 314px;
height: 30px;
float: right;
margin-right: -3.5%;
}
.SetTheAssociatedchild{
width: 120px;
height: 30px;
background: rgba(255,255,255,1);
border: 1px solid rgba(234,234,234,1);
border-radius: 4px;
float: left;
margin-right: 10px;
text-align: center;
line-height: 30px;
/*margin-left: 34px;*/
}
.operatebutton{
margin-left: 20px;
/* margin-top: 16px; */
}
.editbulebutton{
width:120px;
height:30px;
background:rgba(76,172,255,1);
border-radius:2px;
color:#FFF;
text-align: center;
line-height: 30px;
}
.editglybutton{
width:120px;
height:30px;
border:1px solid rgba(205,205,205,1);
border-radius:2px;
color:#999;
text-align: center;
line-height: 30px;
}
.editglybuttonbox{
width: 275px;
margin-bottom: 30px;
margin-right: 20px;
margin-right:7%;
}
.editglybuttonboxs{
width: 275px;
margin-bottom: 30px;
margin-right: 20px;
margin-right:3%;
}
.defalutCancelbtn:hover {
border: 1px solid #B2B2B2;
color: #B2B2B2!important;
}
.gouxuanbule{
color:#4CACFF;
}
.gouxuanwhite{
color:#FFF;
}
.icon-gouxuan{
cursor: pointer;
}
/* 谷歌 */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
appearance: none;
margin: 0;
}
/* 火狐 */
input{
-moz-appearance:textfield;
}
.inputWeight{
text-indent:0.625rem;
}
.columnlocation{
height: 40px;
line-height: 40px;
}
.paddingLF{
padding:0 33px;
}
.width20{
width: 20px;
height: 20px;
text-align: center;
}
.defalutSubmitbtn,.defalutCancelbtn{
cursor: pointer;
}
.mb290{
margin-bottom:290px;
}
.Spinlarge{
text-align: center;
width: 100%;
margin-top: 25px;
margin-bottom: 25px;
}
.DDred{
color:#DD1717;
}
.color-666{
color:#666666 !important;
}
.color-05101A{
color:#05101A !important;
}
.ec_graduation_name{
margin-right:20px !important;
}
.column-width575{
color: transparent !important;
}
.column-width130{
width: 130px !important;
height: 40px;
}
.ListTableLine li>span {
max-width: 550px !important;
}
.graduateRequirement .clearfix .column-1 {
width: 76px!important;
}
.newrightcalculatebutton{
width: 50px;
height: 25px;
border: 1px solid rgba(76,172,255,1);
border-radius: 1px;
line-height: 25px;
text-align: center;
margin-top: 7px;
cursor: pointer;
color: rgba(76,172,255,1);
}
.newrightcalculatebuttons{
width: 50px;
height: 25px;
border: 1px solid rgba(76,172,255,1);
border-radius: 1px;
line-height: 25px;
text-align: center;
margin-top:9px;
cursor: pointer;
color: rgba(76,172,255,1);
}
.columnbox{
height: 53px;
overflow: hidden;
}
.ant-modal-mask {
background-color: rgba(5,16,26,0.4);
}
.ecmodeldelet{
top:300px;
}
.ecmodeldelet .ant-modal-header{
padding: 0px 24px;
}
.ecmodeldelet .ant-modal-title{
padding: 0px 15px;
text-align: center;
box-sizing: border-box;
line-height: 70px;
height: 70px;
border-radius: 10px 10px 0px 0px;
font-size: 16px;
font-weight: bold;
}
.bor-red {
border: 1px solid #db0505 !important;
}
.ml93{
margin-left:93px;
}
.ml26{
margin-left: 26px;
}
.finishtarget{
width: 69px;
/* height: 48px; */
line-height: 20px;
text-align: center;
margin-right: 48px;
}
.bordereaeaea{
border-bottom: 1px solid transparent !important;
}
.heightimportant{
height: 30px !important;
background-color: #F5F5F5;
}
.heightimportant:focus {
background-color: #fff;
}
.inputWeight:focus {
background-color: #fff;
}
.heightlineimportant{
line-height: 30px !important;
}
.ant-select-selection:hover{
border-color: #d9d9d9 !important;
}
.ant-input:focus {
outline: 0;
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-input{
border-color: #d9d9d9 !important;
}
.ant-select-selection:focus{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-select-selection:active{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.ant-select-selection:focus{
border-color: #d9d9d9 !important;
}
.ant-select-selection{
-webkit-box-shadow: 0 0 0 2px transparent !important;
box-shadow: 0 0 0 2px transparent !important;
}
.mt60{
margin-top:60px;
}

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg class="icon" width="20px" height="20px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path fill="#333333" d="M463.9 804.4c-194.7 0-353.1-158.4-353.1-353.1S269.2 98.2 463.9 98.2 817 256.6 817 451.3 658.6 804.4 463.9 804.4z m0-651.9c-164.8 0-298.8 134-298.8 298.8s134 298.8 298.8 298.8 298.8-134 298.8-298.8-134-298.8-298.8-298.8zM884.9 926.6c-7.2 0-14.4-2.9-19.8-8.6l-198-210.6c-10.3-10.9-9.7-28.1 1.2-38.4 10.9-10.3 28.1-9.8 38.4 1.2l198 210.6c10.3 10.9 9.7 28.1-1.2 38.4-5.2 5-11.9 7.4-18.6 7.4z" /></svg>

After

Width:  |  Height:  |  Size: 674 B

@ -0,0 +1,255 @@
import React, { Component } from 'react';
import classNames from 'classnames'
import axios from 'axios';
import { TPMIndexHOC } from '../../tpm/TPMIndexHOC';
import { SnackbarHOC } from 'educoder'
import { message,Modal,Spin,Icon} from 'antd';
import 'antd/dist/antd.css';
import EcTitleCourseEvaluations from '../ecTitle/ecTitle'
import '../css/ecCourseSupports.css';
import '../css/ecCourseEvaluations.css';
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom';
import Loadable from 'react-loadable';
import Loading from "../../../Loading";
const $ = window.$;
const Curriculumtwo = Loadable({
loader: () => import('./Curriculumtwo'),
loading: Loading,
})
const EcCourseEvaluationsbottom =Loadable({
loader: () => import('../subroute/ecCourseEvaluations/EcCourseEvaluationsbottom'),
loading: Loading,
});
const EcCompletionCalculation =Loadable({
loader: () => import('../subroute/ecCompletion_calculation/EcCompletionCalculation'),
loading: Loading,
});
class Curriculum extends Component {
//课程体系
constructor(props) {
super(props)
this.state= {
classcalue:5,
newec_course_idbottom:"",
course_name:undefined,
course_url:"a",
ecmanager:true,
titine:1,
}
}
componentWillMount(){
// window.document.title = '课程达成评价结果';
}
componentDidMount(){
console.log(this.props);
}
sync_course_data=()=>{
// this.setState({listSpin:true})
// let ec_course_id=this.props.match.params.ec_course_id;
// let Url ='/ec_course_achievement_methods/sync_course_data';
// axios.post(Url, {
// ec_course_id:ec_course_id
// },
// {
// withCredentials: true
// }
// ).then((response) => {
// if(response.data.status===0){
// this.setState({
// // titlemessage: response.data.message+"(支撑关系变更)",
// Modallist: response.data.message,
// Modallisttype:true,
// listSpin:false
// })
// this.UpdateEvaluations();
// }else if(response.data.status===-1){
// this.setState({
// // titlemessage: response.data.message+"(支撑关系变更)",
// Modallist: response.data.message,
// Modallisttype:true,
// listSpin:false
// })
//
// }
// }).catch((error) => {
// console.log(error)
// })
}
onAclick=(i)=>{
console.log("onAclick");
console.log(i);
if(i===1){
this.props.history.push(this.props.match.url+"/ec_course_support_setting/1");
}else if(i===2){
this.props.history.push(this.props.match.url+"/ec_course_reach_setting/2");
}else if(i===3){
this.props.history.push(this.props.match.url+"/score_level/3");
}else if(i===4){
this.props.history.push(this.props.match.url+"/evaluation_methods/4");
}else{
this.props.history.push(this.props.match.url+"/competition_calculation_info/5");
}
this.setState({
titine:i,
})
};
Ontitine=(s)=>{
if(s==="ec_course_support_setting"){
this.setState({
titine:1,
})
}else if(s==="ec_course_reach_setting"){
this.setState({
titine:2,
})
}else if(s==="score_level"){
this.setState({
titine:3,
})
}else if(s==="evaluation_methods"){
this.setState({
titine:4,
})
}else if(s==="competition_calculation_info"){
this.setState({
titine:5,
})
}
};
associatedclass=()=>{
};
deleteassociatedclass=()=>{
}
render() {
let {newec_course_idbottom,titine,classcalue,course_name,course_url,ecmanager,Spintype,calculatesetype,ec_course_id,course_total_scoreaverage,ec_course_targets_count,schooldata,ecComponentState,course_total_score,total_rate_data,ec_course_targets,graduation_list,target_list,target_score,evaluate_result,morelisttype,titlemessage,completiontype,completionlist,ismanager} = this.state;
// console.log("Curriculum");
// console.log(this.props);
// console.log(titine);
return (
<div className="educontent">
<div className="newMain clearfix">
<div className="edu-back-white eacourse">
<div className="clearfix padding20-30 bor-bottom-greyE">
<a href={schooldata&&schooldata.course_setting_url} className="color-grey-9 TrainingLecturer">课程体系</a> >
<a className="TrainingTheory major_name"> {schooldata&&schooldata.ec_course_name} 达成评价详情</a>
{/* <a href="javascript:void(0)" className="fr white-btn edu-blueback-btn mt4">导出培养目标</a> */}
<div className="color-grey-9 mr10">系统根据课程目标课程考核方式与课程目标评价方法一键计算评价课程目标的达成情况 <a className={"color-blue"} onClick={() => window.elasticLayer(3533)}>查看详情</a></div>
{
titine === 4 ?
<span className="Importclassroomdatas" style={{top: '22px'}}>
<a className="white-btn edu-blueback-btn fr mb10 mr10 mt7" target="_blank"
href={'/ec_courses/' + newec_course_idbottom + '/export_ec_course_targets?format=xls'}>导出评价方法</a>
</span>
:titine === 1 ?
<span className="Importclassroomdatas" style={{top: '22px'}}>
<a className="white-btn edu-blueback-btn fr mb10 mr10 mt7"
href={`/ec_courses/${this.props.match.params.ec_course_id}/export_ec_course_targets?format=xls`}
>导出课程目标</a>
</span>
:titine===2?
<div className={"Importclassroomdatas"}>
<span className="" >
<a className="white-btn edu-blueback-btn fr mr10 mt7" style={{top: '22px',display:ecmanager===false?"none":"block"}} target="_blank" href={'/ec_courses/'+ec_course_id+'/export_ec_course_targets?format=xls'}>导出考核方法</a>
</span>
<a className="white-btn edu-blueline-btn fr mr10 mt7 mr20"
onClick={this.associatedclass}
style={{display: course_url === "" && ecmanager === true ? "block" : "none"}}
>关联课堂</a>
<a className="white-btn edu-blueline-btn fr mr10 mt7 mr20"
onClick={this.deleteassociatedclass}
style={{display:course_url!=""&&ecmanager===true?"block":"none"}}
>取消关联</a>
</div>
:""
}
</div>
<div className="padding20-30"style={titine===2||titine===3?{height:"100px"}:{height:"80px"}}
>
<a className="fl SystemParameters" style={titine===1?{display:schooldata&&schooldata.ec_course_support_setting_url===null?"none":"block",color:'#4CACFF'}:{display:schooldata&&schooldata.ec_course_support_setting_url===null?"none":"block",color:'#4D4D4D'}}
onClick={()=>this.onAclick(1)}>1.课程目标</a>
<a className="fl SystemParameters ml40"
style={titine===2?{display:schooldata&&schooldata.ec_course_reach_setting_url===null?"none":"block",color:'#4CACFF'}:{display:schooldata&&schooldata.ec_course_reach_setting_url===null?"none":"block",color:'#4D4D4D'}}
onClick={()=>this.onAclick(2)}>2.课程考核方式与数据来源</a>
<a className="fl SystemParameters4CACFF ml40 "
style={titine===3?{color:'#4CACFF'}:{display:"block",color:'#4D4D4D'}}
onClick={()=>this.onAclick(3)}>3.成绩等级设置</a>
<a className="fl SystemParameters ml40"
style={titine===4?{display:schooldata&&schooldata.evaluation_methods_url===null?"none":"block",color:'#4CACFF'}:{display:schooldata&&schooldata.evaluation_methods_url===null?"none":"block",color:'#4D4D4D'}}
onClick={()=>this.onAclick(4)}
>4.课程目标评价方法</a>
<a className="fl SystemParameters ml40 "
style={titine===5?{display:schooldata&&schooldata.competition_calculation_info_url===null?"none":"block",color:'#4CACFF'}:{display:schooldata&&schooldata.competition_calculation_info_url===null?"none":"block",color:'#4D4D4D'}}
onClick={()=>this.onAclick(5)}
>5.课程达成评价结果</a>
{
titine===5?
<span>
<span className={ismanager===false?"none":""} style={{top: "26px"}}>
<a className="white-btn edu-blueback-btn fr mb10 mr10 mt9" target="_blank" href={"/ec_courses/"+ec_course_id+"/export_evaluation_result.xls"}>导出评价详情</a>
</span>
<span className={ismanager===false?"none":"right newrightcalculatebuttons fr mb10 mr20 "}
onClick={this.newrightcalculatebutton}>计算</span>
</span>
:titine===4?
<span className="fr ml20 SystemParameters" style={{color: '#989898'}}>各环节平均得分*占比之和/各环节总分*占比之和</span>
:titine===3?
<span className="fl SystemParametersysls" style={{display:course_name===null||course_name===undefined?"block":"none",
padding: '0px 0px 0px 0px',textAlign: 'left',width: '100%',color:'#989898'}}>将学生的成绩转换成对应的等级</span>
:titine===2?
<span>
<span className="fl" style={{display:course_name===null||course_name===undefined?"block":"none",padding: '0px 0px 0px 0px',textAlign: 'left',width: '100%',color: '#989898'}}>请在完成配置后使用各项成绩导入模板将本学年所有参与的学生成绩数据导入系统</span>
<span className="Importclassroomdatass" style={{display:course_url===""||ecmanager===false?"none":"block",}}><a onClick={this.sync_course_data} className="white-btn edu-orangeback-btn fr mt2 mr10" style={{width:'112px'}}>导入课堂数据</a></span>
</span>
:""
}
</div>
</div>
<Switch>
{/*Curriculumtwo 测试用*/}
{/*课程目标*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses/:type/1'
render={ (props) => (<Curriculumtwo {...this.props} {...props} {...this.state} Ontitine={(i)=>this.Ontitine(i)} />) }></Route>
{/*课程考核方式与数据来源*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses/:type/2'
render={ (props) => (<Curriculumtwo {...this.props} {...props} {...this.state} Ontitine={(i)=>this.Ontitine(i)}/>) }></Route>
{/*成绩等级设置*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses/:type/3'
render={ (props) => (<Curriculumtwo {...this.props} {...props} {...this.state} Ontitine={(i)=>this.Ontitine(i)}/>) }></Route>
{/*4课程目标评价方法*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses/:type/4'
render={ (props) => (<EcCourseEvaluationsbottom {...this.props} {...props} {...this.state} Ontitine={(i)=>this.Ontitine(i)}/>) }></Route>
{/*5课程达成评价结果*/}
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/courses/:type/5'
render={ (props) => (<EcCompletionCalculation {...this.props} {...props} {...this.state} Ontitine={(i)=>this.Ontitine(i)}/>) }></Route>
</Switch>
</div>
</div>
)
}
}
export default Curriculum;

@ -0,0 +1,32 @@
import React, { Component } from 'react';
class Curriculumtwo extends Component {
//测试用
constructor(props) {
super(props)
// console.log(props);
}
componentWillMount(){
}
componentDidMount(){
// console.log(this.props);
console.log("Curriculumtwo");
console.log(this.props.match.params.type);
this.props.Ontitine(this.props.match.params.type);
}
render() {
// console.log("Curriculumtwo");
// console.log(this.props);
return (
<div className="educontent fl">
<span>测试</span>
</div>
)
}
}
export default Curriculumtwo;

@ -0,0 +1,104 @@
#traningNav {
display: flex
}
#traningNav>li {
float: none !important;
}
/* 最后一个item 占满剩余空间 */
#traningNav>li:last-child{
flex: 1;
}
#traningNav>li>.ecTitle {
width: 24px;
height: 24px;
border: 1px solid rgba(65, 140, 205, 1);
border-radius: 50%;
text-align: center;
line-height: 22px;
display: inline-block;
color: rgba(65, 140, 205, 1) !important;
margin-right: 10px;
}
#traningNav>li>.ecTitles {
line-height: 16px !important;
height: 18px!important;
width: 18px!important;
}
#traningNav>li>.ecTitlefont:hover{
color: rgba(65, 140, 205, 1) !important;
}
.ecimgs3{
background: url("./img/3.png");
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
height: 90px;
line-height: 90px;
width: 235px;
}
.ecimgs2{
background: url("./img/4.png");
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
height: 90px;
line-height: 90px;
width: 190px;
}
.ecimgs11{
background: url("./img/3.png");
background-repeat: no-repeat;
background-size: 100% 100%;
-moz-background-size: 100% 100%;
height: 90px;
line-height: 90px;
width: 146px;
}
.ml18{
margin-left: 18px;
}
.ecimgs{
height: 90px;
line-height: 90px;
}
.ecmarginleft{
margin-left: 23px;
}
#traningNav>li>.ecTitlefontFFF{
color:#fff !important;
}
#traningNav>li>.ecTitleFFF {
width: 24px;
height: 24px;
border: 1px solid #fff;
border-radius: 50%;
text-align: center;
line-height: 22px;
display: inline-block;
color: #fff !important;
margin-right: 10px;
}
.traningNavs{
padding: 0px 0px 0px 0px !important;
}
.traningNavs>li{
padding: 0px 10px 30px 10px !important;
}
.mb0{
margin-bottom: 0px !important;
}
.info2{
width:232px;
text-align: center;
}
.info1{
width: 206px;
text-align: center;
}

@ -0,0 +1,100 @@
import React, { Component } from 'react';
import './ecTitle.css';
class EcTitleCourseEvaluations extends Component {
constructor(props) {
super(props)
this.state = {
schooldata:{},
ecComponentState:"",
ecpaths:""
}
}
componentWillReceiveProps(nextProps){
const {schooldata,ecComponentState,ecpath}=nextProps;
this.setState({
schooldata:schooldata,
ecComponentState:ecComponentState,
ecpaths:ecpath
})
}
render() {
let{schooldata,ecComponentState,ecpaths}=this.state;
return (
<div>
<div className="mb10 mt10 eaSystemp">
<a href={schooldata.user_url}>{schooldata.user_name===undefined?"":schooldata.user_name+" > "}</a>
<a href={schooldata.school_url}>{schooldata.school_name===undefined?"":schooldata.school_name+"认证"}</a>
<a href={schooldata.major_url}>{schooldata.school_name===undefined?"":" > "+schooldata.major_name+" > "}</a>
<span> {schooldata.school_name===undefined?"":schooldata.year+"届"}</span>
</div>
<ul className="clearfix mb0 traningNavs " id="traningNav" style={{display:ecpaths==='none'?"none":"flex"}}>
<li className={"ecimgs"}>
<a className={"ecTitle ecTitles"} >1</a>
<a className={"ecTitlefont"} href={schooldata.major_training}>培养目标</a>
</li>
<li className={"ecimgs"}>
<a className={"ecTitle ecTitles"} >2</a>
<a className={"ecTitlefont"} href={schooldata.graduation_requirement_url} >毕业要求</a>
</li>
<li className={"ecimgs"}>
<a className={"ecTitle ecTitles"} >3</a>
<a className={"ecTitlefont"} href={schooldata.requirement_vs_objective_url}>毕业要求 vs 培养目标</a>
</li>
<li className={"ecimgs"}>
<a className={"ecTitle ecTitles"} >4</a>
<a className={"ecTitlefont"} href={schooldata.requirement_vs_standard}>毕业要求 vs 通用标准</a>
</li>
<li className={ecpaths==="ecStudentList"?"ecimgs11":"ecimgs"} style={{width: ecpaths==="ecStudentList"?'126px':'83px'}}>
<a className={ ecpaths==="ecStudentList"?"ml18 ecTitleFFF ecTitles":"ecTitle"} >5</a>
<a className={ ecpaths==="ecStudentList"?"ecTitlefontFFF":"ecTitlefont"} href={schooldata.students_url}>学生</a>
</li>
<li className={ecpaths==="ec_course_support_setting"||ecpaths==="show"?"ecimgs11":"ecimgs"}>
<a className={ ecpaths==="ec_course_support_setting"||ecpaths==="show"?"ml18 ecTitleFFF ecTitles":"ecTitle ecTitles"} >6</a>
<a className={ ecpaths==="ec_course_support_setting"||ecpaths==="show"?"ecTitlefontFFF":"ecTitlefont"} href={schooldata.course_setting_url}>课程体系</a>
</li>
<li className={ecpaths==="requirement_vs_courses"?"ecimgs3":"ecimgs"}>
<a className={ ecpaths==="requirement_vs_courses"?"ecmarginleft ecTitleFFF ecTitles":"ecTitle ecTitles"} >7</a>
<a className={ ecpaths==="requirement_vs_courses"?"ecTitlefontFFF":"ecTitlefont"} href={schooldata.requirement_vs_courses}>课程体系 vs 毕业要求</a>
</li>
<li className={ecpaths==="reach_calculation_info"?"ecimgs2 info2":"ecimgs"}>
<a className={ ecpaths==="reach_calculation_info"?"ecTitleFFF ml18 ecTitles":"ecTitle ecTitles"} >8</a>
<a className={ ecpaths==="reach_calculation_info"?"ecTitlefontFFF":"ecTitlefont"} href={schooldata.reach_calculation_info_url}>达成度评价结果</a>
</li>
{/*<li className={ecComponentState==="ecCourseSupports"?"active edu-menu-panel":"edu-menu-panel"}>*/}
{/*<a>毕业要求</a>*/}
{/*<i className="iconfont icon-xiajiantou font-14 ml5" style={{display:ecComponentState==="ecCourseSupports"?"inline-block":"none"}}></i>*/}
{/*<ul className="edu-menu-list" style={{width:'200px',right:'unset',top:'34px'}}>*/}
{/*<li><a href={schooldata.major_training} >专业培养目标</a></li>*/}
{/*<li><a href={schooldata.graduation_requirement_url} >毕业要求指标点</a></li>*/}
{/*<li><a href={schooldata.requirement_vs_objective_url} >毕业要求vs培养目标</a></li>*/}
{/*<li><a href={schooldata.requirement_vs_standard} >毕业要求vs通用要求</a></li>*/}
{/*<li><a href={schooldata.requirement_vs_courses} >毕业要求vs课程体系</a></li>*/}
{/*</ul>*/}
{/*</li>*/}
{/*<li className={ecComponentState==="ecCourseEvaluations"?"active edu-menu-panel":"edu-menu-panel"}>*/}
{/*<a href={schooldata.course_setting_url}>课程配置</a>*/}
{/*</li>*/}
{/*<li className={ecComponentState==="ecCompletion"?"active edu-menu-panel":"edu-menu-panel"}>*/}
{/*<a>达成度计算</a>*/}
{/*<i className="iconfont icon-xiajiantou font-14 ml5" style={{display:ecComponentState==="ecCompletion"?"inline-block":"none"}}></i>*/}
{/*<ul className="edu-menu-list" style={{width:'200px',right:'unset',top:'34px'}}>*/}
{/*<li><a href={schooldata.completion_calculation_url}>课程达成计算</a></li>*/}
{/*<li><a href={schooldata.reach_calculation_info_url}>毕业要求指标点达成计算</a></li>*/}
{/*</ul>*/}
{/*</li>*/}
{/*<a className="fr color-grey-6 font-16" href={schooldata.go_back_url}>返回</a>*/}
</ul>
</div>
)}
}
export default EcTitleCourseEvaluations;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1,809 @@
import React, { Component } from 'react';
import classNames from 'classnames'
import axios from 'axios';
// import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC';
import { SnackbarHOC } from 'educoder'
import { message,Modal,Spin,Icon} from 'antd';
import 'antd/dist/antd.css';
import EcTitleCourseEvaluations from '../../ecTitle/ecTitle'
import '../../css/ecCourseSupports.css';
import '../../css/ecCourseEvaluations.css';
const $ = window.$;
class EcCompletionCalculation extends Component {
constructor(props) {
super(props)
this.state={
schooldata:{},
ecComponentState:"ecCompletion",
course_total_score:[],
ec_course_targets:0,
graduation_list:[],
target_list:[],
target_score:[],
evaluate_result:"",
ec_course_targets_count:0,
new_target_ec_year_id:0,
total_rate_data:undefined,
calculatetype:false,
ec_course_id:0,
morelisttype:false,
titlemessage:"提示",
completiontype:false,
completionlist:"",
course_total_scoreaverage:0,
calculatesetype:false,
Spintype:false,
ismanager:false
}
}
componentWillMount(){
window.document.title = '课程达成评价结果';
}
componentDidMount(){
let ec_course_id =this.props.match.params.ec_course_id;
this.UpdateClassData(true);
const Url =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id;
axios.get(Url, {
withCredentials: true,
})
.then((response) => {
if(response.status===200){
// if(response.data.allow_visit===false){
// window.location.href="/403"
// }
this.setState({
schooldata:response.data,
ec_course_id:ec_course_id
})
}
})
.catch(function (error) {
console.log(error);
});
}
targetsget_navigation_data=(ec_year_id,ec_course_id)=>{
const Url =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id;
axios.get(Url, {
withCredentials: true,
})
.then((response) => {
if(response.status===200){
// if(response.data.allow_visit===false){
// window.location.href="/403"
// }
this.setState({
schooldata:response.data,
ec_course_id:ec_course_id
})
}
})
.catch(function (error) {
console.log(error);
});
}
showmorelist=()=>{
this.setState({
morelisttype:false
})
this.UpdateClassData(false)
}
UpdateClassData=(key)=>{
let {calculatetype} =this.state;
let ec_course_id =this.props.match.params.ec_course_id;
this.setState({
ec_course_id:ec_course_id
})
const Arl =`/ec_courses/`+ec_course_id+`/calculation_info_data`;
axios.get(Arl, {
withCredentials: true,
})
.then((response) => {
if(response.status===200){
// var list=[];
// if(key===true){
// for(var i=0; i<response.data.course_total_score.length;i++){
// if(i<10){
// list.push(response.data.course_total_score[i])
// }
// }
// }else{
// list=response.data.course_total_score
// }
// let newgraduation_list= response.data.graduation_list.reverse();
let newmorelisttype=false;
if(response.data.course_total_score>10){
newmorelisttype=true
}
let course_total_scoreaverage;
let newlist=response.data.course_total_score[response.data.course_total_score.length-1].total_rate;
for(var i=0; i<newlist.length;i++){
if(i===newlist.length-1){
course_total_scoreaverage=newlist[i].total_score
}
}
this.setState({
evaluate_result:response.data.evaluate_result,
course_total_score:response.data.course_total_score[response.data.course_total_score.length-1].total_rate,
total_rate_data:response.data.course_total_score[response.data.course_total_score.length-1].total_rate.length,
graduation_list:response.data.graduation_list,
target_list:response.data.target_list,
target_score:response.data.target_score,
ec_course_targets_count:response.data.ec_course_targets_count,
morelisttype:newmorelisttype,
course_total_scoreaverage:course_total_scoreaverage,
ismanager:response.data.is_manager
})
// ec_course_targets:response.data.ec_course_targets,
this.targetsget_navigation_data(response.data.ec_year_id,ec_course_id)
if(calculatetype===true){
this.setState({
calculatetype:false,
completiontype:true,
completionlist:'刷新列表数据成功',
calculatesetype:true
})
}
}
})
.catch(function (error) {
console.log(error);
});
//
// let newcourse_total_score=[
// {
// student_scores:{
// name: "黎子豪",
// student_number: "13408100113",
// target_info: [
// {position: 1, score: 73.3},
// {position: 2, score: 71.8},
// {position: 3, score: 92.2},
// {position: 4, score: 82.1},
// {position: 5, score: 87.7}
// ],
// total_score: 81.4
// }
// },{
// total_rate:[
// {position: 1, score: 65.35, rate: 0.1},
// {position: 2, score: 68.81, rate: 0.1},
// {position: 3, score: 68.34, rate: 0.1},
// {position: 4, score: 78.09, rate: 0.35},
// {position: 5, score: 77, rate: 0.35},
// {total_score: 74.5},
// ]
// }
// ]
//
// var list=[];
// if(key===true){
// for(var i=0; i<newcourse_total_score.length;i++){
// if(i<10){
// list.push(newcourse_total_score[i])
// }
// }
// }else{
// list=newcourse_total_score
// }
// let graduation_list=[
// {
// ec_graduation_name: "5-1",
// ec_subitem_content: "能够针对计算机系统的设计、开发、部署、运行和维护等方面的复杂工程问题,开发、选择与使用恰当的技术、资源、现代工程工具和信息技术工具,进行科学合理的预测与模拟,并充分认识到问题的复杂性与解决手段的局限性。",
// reach_real_target: 0.078,
// reach_target: 0.07,
// result: "达成",
// target_position: [0, 0, 0, 1, 0],
// weight: 0.1
// }
// ]
// let newgraduation_list= graduation_list.reverse();
// this.setState({
// course_total_score:list,
// total_rate_data:newcourse_total_score[newcourse_total_score.length-1].total_rate.length,
// graduation_list:newgraduation_list,
// evaluate_result:false,
// target_list:[
// {
// content: "理解数据管理技术和数据库技术的发展,区分不同数据模型的作用和特点,描述数据库系统的类型、结构、数据独立性。",
// real_grade: 65.35,
// result: "达成",
// standard_grade: 65,
// weigths: 0.1
// }
// ],
// target_score:[
// {average_score: 65.35,
// ec_course_targets_count: 5,
// from50: [9, 20.45],
// from60: [13, 29.55],
// from70: [14, 31.82],
// from80: [3, 6.82],
// from90: [1, 2.27],
// from_down: [4, 0.09],
// graduation_list: [],
// low_score: 40,
// top_score: 93.4}
// ],
// ec_course_targets_count:5
//
// })
// if(calculatetype===true){
// message.success('刷新列表数据成功!');
// this.setState({
// calculatetype:false,
// completiontype:true,
// completionlist:'刷新列表数据成功!'
// })
// }
}
newrightcalculatebutton=()=>{
this.setState({
Spintype:true
})
let {ec_course_id}=this.state;
const Orl =`/ec_courses/`+ec_course_id+`/sync_data`;
axios.get(Orl, {
withCredentials:true,
})
.then((response) => {
if(response.data.status===1){
this.setState({
calculatetype:true,
completiontype:true,
completionlist:'计算成功',
calculatesetype:true,
Spintype:false
})
this.UpdateClassData(true);
}
})
.catch(function (error) {
console.log(error)
});
}
hidecompletion=()=>{
this.setState({
completiontype:false,
completionlist:"",
calculatesetype:false
})
}
render() {
let {Spintype,calculatesetype,ec_course_id,course_total_scoreaverage,ec_course_targets_count,schooldata,ecComponentState,course_total_score,total_rate_data,ec_course_targets,graduation_list,target_list,target_score,evaluate_result,morelisttype,titlemessage,completiontype,completionlist,ismanager} = this.state;
let TargetresList = (length) => {
let target_listres = [];
for(let i = 0; i < length; i++) {
// target_listres.push(<span className="column-1 operationleft color-666" key={i}>目标{length-i}</span>)
// target_listres.push(<span className="column-2 operationleft color-666" key={i}>目标{i+1}</span>)
target_listres.push(<span className="column-1 operationright color-666" key={i}>目标{length-i}</span>)
}
return target_listres
}
let TargetresLists = (length) => {
let target_listress = [];
for(let i = 0; i < length; i++) {
// target_listres.push(<span className="column-1 operationleft color-666" key={i}>目标{length-i}</span>)
target_listress.push(<span className="column-2 operationleft color-666" key={i}>目标{i+1}</span>)
// target_listres.push(<span className="column-1 operationright color-666" key={i}>目标{length-i}</span>)
}
return target_listress
}
let TargetresContentList = (length,value) => {
let target_listres = [];
if(value!=undefined){
for(let i = 0; i < length; i++) {
if(value[i]===1){
target_listres.push(<span className="column-1 operationright color-green" key={i}><i class="iconfont icon-gouxuan color-green font-16 mr5"></i></span>)
}else{
target_listres.push(<span className="column-1 operationright color-666" key={i}><i class="iconfont icon-guanbi font-14 mr5"></i></span>)
}
}
target_listres.reverse()
return target_listres
}
}
let Total_rate_dataList = (value) => {
let target_listres = [];
if(value!=undefined){
for(let i = 0; i < value.length; i++) {
if(i===value.length-1){
target_listres.push(<span className="column-1 operationright" key={i}>
{/*<div className="color-red">{value[i].total_score}</div>*/}
<div className="color-red">100%</div>
</span>)
}else{
target_listres.push(<span className={i===0?" column-2 operationleft":"column-2 operationleft"} key={i}>
{/*<div>{value[i].score}</div>*/}
{/*<div className="color-redFF">占比{(value[i].rate*100).toFixed(2)}%</div>*/}
<div>
{(value[i].rate*100).toFixed(2)}%
</div>
</span>)
}
}
return target_listres
}else{
target_listres.push(<span className="column-1 operationright">
{/*<div className="color-red">{value[i].total_score}</div>*/}
<div className="">--</div>
</span>)
return target_listres
}
}
let newTotal_rate_dataList = (length,value) => {
let target_listres = [];
if(value!=undefined){
for(let i = 0; i < value.length; i++) {
// if(i===0){
// target_listres.push(<span className="column-2 color-05101A" key={i}>
// <div>{value[i].score.toFixed(2)}</div>
// </span>)
// }else{
// target_listres.push(<span className="column-2 color-05101A" key={i}>
// <div>{value[i].score.toFixed(2)}</div>
// </span>)
// }
if(i<value.length-1){
target_listres.push(<span className="column-2 color-05101A" key={i}>
<div>{value[i].score.toFixed(2)}</div>
</span>)
}
}
return target_listres
}
}
return (
<div className="newMain clearfix">
<Modal
title={titlemessage}
visible={completiontype}
className={"ecmodeldelet"}
closable={false}
footer={null}
>
<div className="task-popup-content">
<div className="task-popup-text-center font-14">{completionlist}</div>
</div>
{
calculatesetype===true?
<div className="task-popup-submit clearfix"
style={{width:'69px'}}
>
<a className="task-btn task-btn-orange fr"
style={{fontWeight: '400'}}
onClick={this.hidecompletion}
>知道啦</a>
</div>
:
<div className="task-popup-submit clearfix">
<a onClick={this.hidecompletion} className="task-btn fl">取消</a>
<a className="task-btn task-btn-orange fr"
onClick={this.hidecompletion}
>确定</a>
</div>
}
</Modal>
<div className="educontent mb290">
{/*<EcTitleCourseEvaluations*/}
{/* {...this.props}*/}
{/* schooldata={schooldata}*/}
{/* ecComponentState={'ecCompletion'}*/}
{/* ecpath={"show"}*/}
{/*/>*/}
{/*<div className="edu-back-white eacourse">*/}
{/* <div className="clearfix padding20-30 bor-bottom-greyE">*/}
{/* <a href={schooldata.course_setting_url} className="color-grey-9 TrainingLecturer">课程体系</a> >*/}
{/* <a className="TrainingTheory major_name"> {schooldata.ec_course_name} 达成评价详情</a>*/}
{/* /!* <a href="javascript:void(0)" className="fr white-btn edu-blueback-btn mt4">导出培养目标</a> *!/*/}
{/* <div className="color-grey-9 mr10">系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 <a className={"color-blue"} onClick={() => window.elasticLayer(3533)}>查看详情</a></div>*/}
{/* </div>*/}
{/* <div className="padding20-30" id="training_objective_contents"*/}
{/* style={{*/}
{/* position: 'relative'*/}
{/* }}*/}
{/* >*/}
{/* <a className="fl SystemParameters" style={{display:schooldata.ec_course_support_setting_url===null?"none":"block"}}*/}
{/* href={schooldata.ec_course_support_setting_url}>1.课程目标</a>*/}
{/* <a className="fl SystemParameters ml40"*/}
{/* style={{display:schooldata.ec_course_reach_setting_url===null?"none":"block"}}*/}
{/* href={schooldata.ec_course_reach_setting_url}>2.课程考核方式与数据来源</a>*/}
{/* <a className="fl SystemParameters4CACFF ml40 color4D4D4D"*/}
{/* href={schooldata.score_level_setting_url}*/}
{/* >3.成绩等级设置</a>*/}
{/* <a className="fl SystemParameters ml40"*/}
{/* style={{display:schooldata.evaluation_methods_url===null?"none":"block"}}*/}
{/* href={schooldata.evaluation_methods_url}>4.课程目标评价方法</a>*/}
{/* <a className="fl SystemParameters ml40"*/}
{/* style={{display:schooldata.competition_calculation_info_url===null?"none":"block",color:'#4CACFF'}}*/}
{/* href={schooldata.competition_calculation_info_url}>5.课程达成评价结果</a>*/}
{/* /!* <span className="right ml20 SystemParameters">课程体系:*/}
{/* {*/}
{/* evaluate_result===false?<span className="Systemnum">未达成</span>:<span className="Systemnum color-green">达成</span>*/}
{/* }*/}
{/* </span> *!/*/}
{/* <span className={ismanager===false?"none":"right newrightcalculatebutton"} */}
{/* style={{*/}
{/* marginLeft: '26px',*/}
{/* position: 'absolute',*/}
{/* right: '157px'*/}
{/* }}*/}
{/* onClick={this.newrightcalculatebutton}>计算</span>*/}
{/* <span className={ismanager===false?"none":"Importclassroomdata"} style={{top: "26px"}}>*/}
{/* <a className="white-btn edu-blueback-btn fr mb10 mr10" target="_blank" href={"/ec_courses/"+ec_course_id+"/export_evaluation_result.xls"}>导出评价详情</a>*/}
{/* </span>*/}
{/* </div>*/}
{/*</div>*/}
<div className="ListTableLine newSystem mb20" id="school_major_list">
<p className="clearfix padding10im" >
<span className="column-1 color-666">课程目标</span>
<span className="column-1 operationright color-666">达成结果</span>
<span className="column-1 operationright color-666">达成标准()</span>
<span className="column-1 operationright color-666">实际达成</span>
<span className="column-1 operationright color-666">权重</span>
</p>
{ Spintype===true?<Spin className="Spinlarge" indicator={<Icon type="loading" style={{ fontSize: 30 }} spin />}/>:"" }
{ target_list.length===0&&Spintype===false?
<li className={ "clearfix newtarget_scoreclass lipadding10im"}>
<span className="column-1 color-05101A">--</span>
<span className="column-575 color-05101A">--</span>
<span className={"column-1 operationright Systemnum"}>--</span>
<span className="column-1 operationright color-05101A">--</span>
<span className="column-1 operationright">--</span>
<span className="column-1 operationright">--</span>
</li>:""}
{Spintype===false?target_list.map((item,key)=>{
return(
<li className={key+1===target_list.length?"clearfix newtarget_target lipadding10im":"clearfix newtarget_scoreclass lipadding10im"} key={key}>
<span className="column-1 color-05101A">{key+1}</span>
<span className="column-575 color-05101A">{item.content}</span>
<span className={item.result==="未达成"?"column-1 operationright Systemnum":"column-1 operationright color-green"}>{item.result}</span>
<span className="column-1 operationright color-05101A">{item.standard_grade}</span>
<span className="column-1 operationright">{item.real_grade}</span>
<span className="column-1 op erationright">{item.weigths}</span>
</li>
)
}):""
}
</div>
<div className="edu-back-white eacourse">
<div className="padding1030" id="training_objective_contents">
<span className="fl SystemParameters lineheight60" style={{height:'46px'}}> 毕业要求指标点达成评价结果</span>
<span className="right ml20 SystemParameters" style={{height:'46px'}}><span className="color-green"><i class="iconfont icon-gouxuan color-green font-16 mr5"></i></span> <i class="iconfont icon-guanbi font-14 mr5"></i></span>
</div>
</div>
<div className="ListTableLine newSystem mb20 graduateRequirement " id="school_major_list">
{
graduation_list.length===0?
<p className="clearfix lipadding20im" style={{minWidth:'1200px'}}>
<span className="column-1 color-666 mr16">毕业要求</span>
<span className="nowrap329">{5}</span>
<span className="column-1 operationright color-666">达成结果</span>
<span className="column-1 operationright color-666">达成目标值</span>
<span className="column-1 operationright color-666">达成实际值</span>
<span className="column-1 operationright color-666">课程权重</span>
{TargetresList(5)}
</p>
:""
}
{ Spintype===true?<Spin className="Spinlarge" indicator={<Icon type="loading" style={{ fontSize: 30 }} spin />}/>:"" }
{
graduation_list.length===0&&Spintype===false?
<li className={'clearfix newtarget_scoreclass marlr19'} style={{minWidth:'1137px'}}>
{/* <span className="column-1 color-05101A ec_graduation_name">{item.ec_graduation_name}</span> */}
<span className="column-1 color-05101A ec_graduation_name">{1}</span>
<span className="column-500 color-05101A">{"--"}</span>
<span className={"column-1 operationright Systemnum mrj15"}>{"--"}</span>
<span className="column-1 operationright color-05101A">{"--"}</span>
<span className="column-1 operationright">{"--"}</span>
<span className="column-1 operationright"> <a href={schooldata.requirement_vs_courses} style={{color:'rgb(76, 172, 255)'}}>立即配置</a></span>
{TargetresContentList(5,[2,2,2,2,2])}
</li>
:""
}
{
Spintype===false?graduation_list.map((item,key)=>{
if(key===0){
return(
<p key={key} className="clearfix lipadding20im" style={{minWidth: ec_course_targets_count > 5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}>
<span className="column-1 color-666 mr16">毕业要求</span>
<span className="nowrap329">{item.ec_subitem_content}</span>
<span className="column-1 operationright color-666">达成结果</span>
<span className="column-1 operationright color-666">达成目标值</span>
<span className="column-1 operationright color-666">达成实际值</span>
<span className="column-1 operationright color-666">课程权重</span>
{TargetresList(ec_course_targets_count)}
</p>
)
}
}):""
}
{
Spintype===false?graduation_list.map((item,key)=>{
return(
<li className={key+1===target_list.length?"clearfix newtarget_target marlr19":"clearfix newtarget_scoreclass marlr19"} key={key} style={{minWidth: ec_course_targets_count > 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}>
{/* <span className="column-1 color-05101A ec_graduation_name">{item.ec_graduation_name}</span> */}
<span className="column-1 color-05101A ec_graduation_name">{key+1}</span>
<span className="column-500 color-05101A" data-tip-down={item.content}>{item.ec_subitem_content}</span>
<span className={item.result==="未达成"?"column-1 operationright Systemnum mrj15":"column-1 operationright color-green mrj15"}>{item.result}</span>
<span className="column-1 operationright color-05101A">{item.reach_target===null?0:item.reach_target}</span>
<span className="column-1 operationright">{item.reach_real_target===null?0:item.reach_real_target}</span>
{item.weight===null||item.weight===0?<span className="column-1 operationright" ><a href={schooldata.requirement_vs_courses} style={{color:'rgb(76, 172, 255)'}}>立即配置</a></span>:<span className="column-1 operationright">{item.weight}</span>}
{TargetresContentList(ec_course_targets_count,item.target_position)}
</li>
)
}):""
}
</div>
<div className="edu-back-white eacourse">
<div className="padding1030" id="training_objective_contents">
<span className="fl SystemParameters lineheight60" style={{height:'46px'}}>课程总评成绩表</span>
</div>
</div>
<div className="ListTableLine newSystem mb20" id="school_major_list">
<p className="clearfix padding10im" style={{width: total_rate_data > 5 ? (180 * total_rate_data+226+16) : 1200+"px"}}>
{/*<span className="column-1 color-666 mr16 width86">序号</span>*/}
<span className="column-1 color-666 mr16 width86">课程目标</span>
{/*<span className="column-1 color-666 mr16">姓名</span>*/}
{/*<span className="column-1 color-666 mr16">学号</span>*/}
{TargetresLists(total_rate_data-1)}
<span className="column-1 operationright color-666">总评成绩</span>
</p>
{/*style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4.5):1136+"px"}}*/}
{
// course_total_score.map((i,k)=>{
// if(k===course_total_score.length-1){
// return(
// <li className={"clearfix newtarget_scoreclass lipadding10im margin64px"} key={k} style={{width: 113*(total_rate_data+4)>1200?(113*(total_rate_data+4.5))+63:1200+"px"}}>
// <span className="column-1 color-05101A mr16 width86">占比</span>
// {/*colorTransparent*/}
// {/*<span className="column-1 color-05101A ec_graduation_name mr16 colorTransparent"> 平均数 </span>*/}
// {/*<span className="column-1 color-05101A ec_graduation_name mr16 colorTransparent "> 平均数 </span>*/}
// {/* {Total_rate_dataList(total_rate_data-1,i.total_rate)}
// </li>
// )
// }
// }) */}
}
{ Spintype===true?<Spin className="Spinlarge" indicator={<Icon type="loading" style={{ fontSize: 30 }} spin />}/>:"" }
{
Spintype===false? <li className={"clearfix newtarget_scoreclass lipadding10im margin64px"} style={{width: total_rate_data > 5 ? (180 * total_rate_data+226+16) : 1200 + "px"}}>
<span className="column-1 color-05101A mr16 width86">占比</span>
{/*colorTransparent*/}
{/*<span className="column-1 color-05101A ec_graduation_name mr16 colorTransparent"> 平均数 </span>*/}
{/*<span className="column-1 color-05101A ec_graduation_name mr16 colorTransparent "> 平均数 </span>*/}
{Total_rate_dataList(course_total_score)}
{
course_total_score.length===0? <span className="column-1 operationright">--</span>:""
}
</li>:""
}
{/*style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4):1136+"px"}}*/}
{
// course_total_score.map((i,k)=>{
// if(k!=course_total_score.length-1){
// return(
// <li className={"clearfix newtarget_scoreclass lipadding10im"} style={{width: 113*(total_rate_data+4)>1200?(113*(total_rate_data+4.5))+63:1200+"px"}}>
// {/*<span className="column-1 color-05101A mr16 width86">{k+1}</span>*/}
// <span className="column-1 color-05101A mr16 width86">平均分</span>
// {/*<span className="column-1 color-05101A ec_graduation_name mr16">{i.student_scores.name}</span>*/}
// {/*<span className="column-1 color999 ec_graduation_name mr16 ">{i.student_scores.student_number}</span>*/}
// {newTotal_rate_dataList(total_rate_data-1,i.student_scores.target_info)}
// <span className="column-1 color-red operationright">{i.student_scores.total_score.toFixed(2)}</span>
// </li>
// )
// }
// })
}
{
Spintype===false?<li className={"clearfix newtarget_scoreclass lipadding10im bordereaeaea"} style={{width: 113*(total_rate_data+4)>1200?(113*(total_rate_data+4.5))+63:1200+"px"}}>
{/*<span className="column-1 color-05101A mr16 width86">{k+1}</span>*/}
<span className="column-1 color-05101A mr16 width86">平均分</span>
{/*<span className="column-1 color-05101A ec_graduation_name mr16">{i.student_scores.name}</span>*/}
{/*<span className="column-1 color999 ec_graduation_name mr16 ">{i.student_scores.student_number}</span>*/}
{newTotal_rate_dataList(course_total_score-1,course_total_score)}
{/* <span className="column-1 color-red operationright">{course_total_score.length===0?"":course_total_score[course_total_score-1].total_score}</span> */}
{
course_total_score.length===0? <span className="column-1 operationright">--</span>:<span className="column-1 color-red operationright">{course_total_scoreaverage}</span>
}
</li>:""
}
<li class="clearfix newtarget_scoreclass" style={{width: 113*(total_rate_data+4)>1136?113*(total_rate_data+4):1136+"px",display:morelisttype===true?"block":"none"}}>
<a className={"ecmorelist"} onClick={()=>this.showmorelist()}>加载更多</a>
</li>
</div>
<div className="edu-back-white eacourse">
<div className="padding1030" id="training_objective_contents">
<span className="fl SystemParameters lineheight60" style={{height:'46px'}}>课程目标成绩分析</span>
</div>
</div>
<div className="ListTableLine newSystem mb20" id="school_major_list">
<p className="clearfix padding10im">
<span className="column-1 color-666">课程目标</span>
<span className="column-1 color-666">平均分</span>
<span className="column-1 color-666">最高分数</span>
<span className="column-1 color-666">最低分数</span>
<span className="column-1 color-666">90分以上</span>
<span className="column-1 color-666">80-89</span>
<span className="column-1 color-666">70-79</span>
<span className="column-1 color-666">60-69</span>
<span className="column-1 color-666">50-59</span>
<span className="column-1 color-666">低于50分</span>
</p>
{
Spintype===false?target_score.map((i,k)=>{
return(
<li className={"clearfix newtarget_scoreclass lipadding10im"} key={k}>
<span className="column-1 color-05101A">{k+1}</span>
<span className="column-1 color-05101A">{i.average_score}</span>
<span className="column-1 colorFF6800">{i.top_score}</span>
<span className="column-1 color-green">{i.low_score}</span>
<span className="column-1 color-05101A">
<div>{i.from90[0]}</div>
<div className="color999">{(i.from90[1]).toFixed(2)}%</div>
</span>
<span className="column-1 color-05101A">
<div>{i.from80[0]}</div>
<div className="color999">{(i.from80[1]).toFixed(2)}%</div>
</span>
<span className="column-1 color-05101A">
<div>{i.from70[0]}</div>
<div className="color999">{(i.from70[1]).toFixed(2)}%</div>
</span>
<span className="column-1 color-05101A">
<div>{i.from60[0]}</div>
<div className="color999">{(i.from60[1]).toFixed(2)}%</div>
</span>
<span className="column-1 color-05101A">
<div>{i.from50[0]}</div>
<div className="color999">{(i.from50[1]).toFixed(2)}%</div>
</span>
<span className="column-1 color-05101A">
<div>{i.from_down[0]}</div>
<div className="color999">{(i.from_down[1]).toFixed(2)}%</div>
</span>
</li>
)
}):""
}
{ Spintype===true?<Spin className="Spinlarge" indicator={<Icon type="loading" style={{ fontSize: 30 }} spin />}/>:"" }
{target_score.length===0&&Spintype===false?
<li className={"clearfix newtarget_scoreclass lipadding10im"}>
<span className="column-1 color-05101A">--</span>
<span className="column-1 color-05101A">--</span>
<span className="column-1 colorFF6800">--</span>
<span className="column-1 color-green">--</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
<span className="column-1 color-05101A">
<div>--</div>
<div className="color999">--%</div>
</span>
</li>:""}
</div>
</div>
</div>
);
}
}
export default SnackbarHOC() (EcCompletionCalculation);

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save