From eabad1165ab4e3c8ba42497803bff3c76bc8cc67 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 11 Sep 2019 11:22:25 +0800 Subject: [PATCH 01/23] ec department index page --- app/controllers/concerns/paginate_helper.rb | 6 +- app/controllers/ecs/base_controller.rb | 6 +- .../ecs/ec_major_schools_controller.rb | 2 +- app/controllers/ecs/ec_majors_controller.rb | 4 +- .../ecs/major_managers_controller.rb | 3 +- app/controllers/ecs/users_controller.rb | 22 ++ app/controllers/users/base_controller.rb | 8 +- app/libs/util.rb | 2 + app/models/ec_year.rb | 3 + app/queries/application_query.rb | 6 + app/queries/user_query.rb | 28 ++ .../ecs/create_major_manager_service.rb | 25 +- .../ecs/ec_major_schools/index.json.jbuilder | 4 +- app/views/ecs/ec_majors/index.json.jbuilder | 7 +- app/views/ecs/homes/index.json.jbuilder | 2 +- .../ecs/major_managers/create.json.jbuilder | 1 - app/views/ecs/users/index.json.jbuilder | 12 + config/routes.rb | 1 + public/react/config/webpack.config.dev.js | 15 + public/react/config/webpack.config.prod.js | 17 ++ public/react/package.json | 2 + public/react/src/App.js | 9 + public/react/src/AppConfig.js | 2 +- public/react/src/images/ecs/bg.jpg | Bin 0 -> 81209 bytes .../src/modules/ecs/Home/AddMajorModal.js | 173 +++++++++++ .../src/modules/ecs/Home/AddMajorModal.scss | 28 ++ .../src/modules/ecs/Home/AddManagerModal.js | 220 ++++++++++++++ .../src/modules/ecs/Home/AddManagerModal.scss | 34 +++ .../src/modules/ecs/Home/MajorManager.js | 60 ++++ public/react/src/modules/ecs/Home/index.js | 268 ++++++++++++++++++ public/react/src/modules/ecs/Home/index.scss | 127 +++++++++ public/react/src/modules/help/Help.js | 1 - 32 files changed, 1072 insertions(+), 26 deletions(-) create mode 100644 app/controllers/ecs/users_controller.rb create mode 100644 app/queries/user_query.rb delete mode 100644 app/views/ecs/major_managers/create.json.jbuilder create mode 100644 app/views/ecs/users/index.json.jbuilder create mode 100644 public/react/src/images/ecs/bg.jpg create mode 100644 public/react/src/modules/ecs/Home/AddMajorModal.js create mode 100644 public/react/src/modules/ecs/Home/AddMajorModal.scss create mode 100644 public/react/src/modules/ecs/Home/AddManagerModal.js create mode 100644 public/react/src/modules/ecs/Home/AddManagerModal.scss create mode 100644 public/react/src/modules/ecs/Home/MajorManager.js create mode 100644 public/react/src/modules/ecs/Home/index.js create mode 100644 public/react/src/modules/ecs/Home/index.scss diff --git a/app/controllers/concerns/paginate_helper.rb b/app/controllers/concerns/paginate_helper.rb index bbe84a348..7233adebf 100644 --- a/app/controllers/concerns/paginate_helper.rb +++ b/app/controllers/concerns/paginate_helper.rb @@ -3,6 +3,10 @@ module PaginateHelper page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 && params[:per_page].to_i < 50 ? params[:per_page].to_i : opts[:per_page] || 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file diff --git a/app/controllers/ecs/base_controller.rb b/app/controllers/ecs/base_controller.rb index 2cded249a..1ad40d7b3 100644 --- a/app/controllers/ecs/base_controller.rb +++ b/app/controllers/ecs/base_controller.rb @@ -47,6 +47,10 @@ class Ecs::BaseController < ApplicationController page = params[:page].to_i <= 0 ? 1 : params[:page].to_i per_page = params[:per_page].to_i > 0 ? params[:per_page].to_i : 20 - Kaminari.paginate_array(objs).page(page).per(per_page) + if objs.is_a?(Array) + Kaminari.paginate_array(objs).page(page).per(per_page) + else + objs.page(page).per(per_page) + end end end \ No newline at end of file diff --git a/app/controllers/ecs/ec_major_schools_controller.rb b/app/controllers/ecs/ec_major_schools_controller.rb index 058bc888e..b7af447e2 100644 --- a/app/controllers/ecs/ec_major_schools_controller.rb +++ b/app/controllers/ecs/ec_major_schools_controller.rb @@ -20,7 +20,7 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController @count = major_schools.count #检索后的数量,小于或等于全部数量 @major_schools = paginate(major_schools.includes(:users, :ec_major)) - @template_major_school = current_school.ec_major_schools.is_template.first #示例专业 + @template_major_school = EcMajorSchool.is_template.first #示例专业 end def create diff --git a/app/controllers/ecs/ec_majors_controller.rb b/app/controllers/ecs/ec_majors_controller.rb index 7b14237dc..e8daaf008 100644 --- a/app/controllers/ecs/ec_majors_controller.rb +++ b/app/controllers/ecs/ec_majors_controller.rb @@ -1,7 +1,7 @@ class Ecs::EcMajorsController < Ecs::BaseController def index - school_major_subquery = current_school.ec_major_schools.select(:ec_major_id) #学校已选择的专业 - ec_majors = EcMajor.where.not(id: school_major_subquery) + @major_ids = current_school.ec_major_schools.pluck(:ec_major_id) #学校已选择的专业 + ec_majors = EcMajor.all if params[:search].present? ec_majors = ec_majors.search_name_or_code(params[:search]) diff --git a/app/controllers/ecs/major_managers_controller.rb b/app/controllers/ecs/major_managers_controller.rb index da5682734..d2515745b 100644 --- a/app/controllers/ecs/major_managers_controller.rb +++ b/app/controllers/ecs/major_managers_controller.rb @@ -3,7 +3,8 @@ class Ecs::MajorManagersController < Ecs::BaseController before_action :check_manager_permission! def create - @user = Ecs::CreateMajorManagerService.call(current_major_school, params[:user_id]) + Ecs::CreateMajorManagerService.call(current_major_school, params[:user_ids]) + render_ok rescue Ecs::CreateMajorManagerService::Error => ex render_error(ex.message) end diff --git a/app/controllers/ecs/users_controller.rb b/app/controllers/ecs/users_controller.rb new file mode 100644 index 000000000..139893efc --- /dev/null +++ b/app/controllers/ecs/users_controller.rb @@ -0,0 +1,22 @@ +class Ecs::UsersController < Ecs::BaseController + skip_before_action :check_user_permission! + before_action :check_manager_permission! + + def index + users = UserQuery.call(params) + + @count = users.count + @users = paginate users.includes(user_extension: [:school, :department]) + @manager_ids = current_major_school.ec_major_school_users.pluck(:user_id) + end + + private + + def current_major_school + @_ec_major_school ||= EcMajorSchool.find(params[:ec_major_school_id]) + end + + def current_school + @_current_school ||= current_major_school.school + end +end diff --git a/app/controllers/users/base_controller.rb b/app/controllers/users/base_controller.rb index 3ba6940f5..128dc539b 100644 --- a/app/controllers/users/base_controller.rb +++ b/app/controllers/users/base_controller.rb @@ -55,7 +55,13 @@ class Users::BaseController < ApplicationController page = page_value per_page = per_page_value - return Kaminari.paginate_array(objs).page(page).per(per_page) unless opts[:special] && observed_logged_user? + unless opts[:special] && observed_logged_user? + if objs.is_a?(Array) + return Kaminari.paginate_array(objs).page(page).per(per_page) + else + return objs.page(page).per(per_page) + end + end # note: 为实现第一页少一条记录,让前端放置新建入口 if page == 1 diff --git a/app/libs/util.rb b/app/libs/util.rb index f39ce2b58..ae2e4b80b 100644 --- a/app/libs/util.rb +++ b/app/libs/util.rb @@ -45,6 +45,8 @@ module Util def conceal(str, type = nil) str = str.to_s + return if str.blank? + case type when :phone then "#{str[0..2]}***#{str[-4..-1]}" when :email then "#{str[0..2]}***#{str[str.rindex('@')..-1]}" diff --git a/app/models/ec_year.rb b/app/models/ec_year.rb index 69ae4c291..153edcf16 100644 --- a/app/models/ec_year.rb +++ b/app/models/ec_year.rb @@ -9,4 +9,7 @@ class EcYear < ApplicationRecord has_many :ec_graduation_requirements, dependent: :destroy has_many :ec_graduation_subitems, through: :ec_graduation_requirements has_many :ec_year_students, dependent: :destroy + + has_many :ec_course_users, dependent: :destroy + has_many :managers, through: :ec_course_users, source: :user end diff --git a/app/queries/application_query.rb b/app/queries/application_query.rb index 3a92cc6e8..c66af94c0 100644 --- a/app/queries/application_query.rb +++ b/app/queries/application_query.rb @@ -1,3 +1,9 @@ class ApplicationQuery include Callable + + private + + def strip_param(key) + params[key].to_s.strip.presence + end end \ No newline at end of file diff --git a/app/queries/user_query.rb b/app/queries/user_query.rb new file mode 100644 index 000000000..326665fe9 --- /dev/null +++ b/app/queries/user_query.rb @@ -0,0 +1,28 @@ +class UserQuery < ApplicationQuery + attr_reader :params + + def initialize(params) + @params = params + end + + def call + users = User.where(type: 'User') + + # 真实姓名 + if name = strip_param(:name) + users = users.where('LOWER(CONCAT(users.lastname, users.firstname)) LIKE ?', "%#{name.downcase}%") + end + + # 单位名称 + if school = strip_param(:school) + users = users.joins(user_extension: :school).where('schools.name LIKE ?', "%#{school}%") + end + + # 职业 + if (identity = strip_param(:identity)) && UserExtension.identities.keys.include?(identity) + users = users.joins(:user_extension).where(user_extensions: { identity: identity }) + end + + users + end +end \ No newline at end of file diff --git a/app/services/ecs/create_major_manager_service.rb b/app/services/ecs/create_major_manager_service.rb index befe80706..c955bffed 100644 --- a/app/services/ecs/create_major_manager_service.rb +++ b/app/services/ecs/create_major_manager_service.rb @@ -3,29 +3,30 @@ class Ecs::CreateMajorManagerService < ApplicationService MAJOR_MANAGER_COUNT_LIMIT = 5 # 专业管理员数量限制 - attr_reader :major_school, :user_id + attr_reader :major_school, :user_ids - def initialize(major_school, user_id) + def initialize(major_school, user_ids) @major_school = major_school - @user_id = user_id + @user_ids = user_ids end def call raise Error, '示例专业不能添加管理员' if major_school.template_major? - user = User.find_by(id: params[:user_id]) - raise Error, '该用户不存在' if user.blank? + @user_ids = User.where(id: user_ids).pluck(:id) - if major_school.ec_major_school_users.exists?(user_id: user.id) - raise Error, '该用户已经是该专业的管理员了' + if major_school.ec_major_school_users.exists?(user_id: user_ids) + raise Error, '所选用户中存在该专业的管理员' end - if major_school.ec_major_school_users.count >= MAJOR_MANAGER_COUNT_LIMIT - raise Error, '该专业管理员数量已达上限' + if major_school.ec_major_school_users.count + user_ids.count > MAJOR_MANAGER_COUNT_LIMIT + raise Error, "该专业管理员数量超过上限(#{MAJOR_MANAGER_COUNT_LIMIT}人)" end - major_school.ec_major_school_users.create!(user: user) - - user + ActiveRecord::Base.transaction do + user_ids.each do |user_id| + major_school.ec_major_school_users.create!(user_id: user_id) + end + end end end \ No newline at end of file diff --git a/app/views/ecs/ec_major_schools/index.json.jbuilder b/app/views/ecs/ec_major_schools/index.json.jbuilder index 0924b71ea..312abd26b 100644 --- a/app/views/ecs/ec_major_schools/index.json.jbuilder +++ b/app/views/ecs/ec_major_schools/index.json.jbuilder @@ -3,7 +3,7 @@ json.count @count # 示例专业 json.template_ec_major_school do - json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school + json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: @template_major_school if @template_major_school end # 专业 @@ -11,5 +11,5 @@ json.ec_major_schools @major_schools do |ec_major_school| json.partial! 'ecs/ec_major_schools/shared/ec_major_school', ec_major_school: ec_major_school # 专业管理员 - json.major_managers ec_major_school.users, partial: 'ecs/ec_major_schools/shared/ec_major_school', as: :user + json.major_managers ec_major_school.users, partial: 'users/user_simple', as: :user end diff --git a/app/views/ecs/ec_majors/index.json.jbuilder b/app/views/ecs/ec_majors/index.json.jbuilder index 34ee9a907..df3373fed 100644 --- a/app/views/ecs/ec_majors/index.json.jbuilder +++ b/app/views/ecs/ec_majors/index.json.jbuilder @@ -1,2 +1,7 @@ json.count @count -json.es_majors @ec_majors, partial: 'ecs/majors/shared/ec_major', as: :ec_major +json.ec_majors do + json.array! @ec_majors.each do |major| + json.extract! major, :id, :name, :code + json.selected @major_ids.include?(major.id) + end +end diff --git a/app/views/ecs/homes/index.json.jbuilder b/app/views/ecs/homes/index.json.jbuilder index 9bf21f056..8546f6c4a 100644 --- a/app/views/ecs/homes/index.json.jbuilder +++ b/app/views/ecs/homes/index.json.jbuilder @@ -13,4 +13,4 @@ json.school do json.name current_school.name end -json.school_managers @school_managers, partial: 'ecs/shared/user', as: :user +json.school_managers @school_managers, partial: 'users/user_simple', as: :user diff --git a/app/views/ecs/major_managers/create.json.jbuilder b/app/views/ecs/major_managers/create.json.jbuilder deleted file mode 100644 index ff7ff01e5..000000000 --- a/app/views/ecs/major_managers/create.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.partial! 'ecs/shared/user', user: @user diff --git a/app/views/ecs/users/index.json.jbuilder b/app/views/ecs/users/index.json.jbuilder new file mode 100644 index 000000000..0109b9ca0 --- /dev/null +++ b/app/views/ecs/users/index.json.jbuilder @@ -0,0 +1,12 @@ +json.count @count +json.users do + json.array! @users.each do |user| + json.id user.id + json.name user.real_name + json.identity user.identity + json.school_name user.school_name + json.department_name user.department_name + json.phone Util.conceal(user.phone, :phone) + json.manager @manager_ids.include?(user.id) + end +end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index e47c28fe6..d043eff96 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -708,6 +708,7 @@ Rails.application.routes.draw do # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 scope module: :ecs do resources :ec_major_schools, only: [] do + resources :users, only: [:index] resources :major_managers, only: [:create, :destroy] resources :ec_years, only: [:index, :create, :destroy] end diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js index 8045580e9..18d1a4002 100644 --- a/public/react/config/webpack.config.dev.js +++ b/public/react/config/webpack.config.dev.js @@ -197,6 +197,21 @@ module.exports = { }, ], }, + { + test: /\.scss$/, + use: [ + require.resolve("style-loader"), + { + loader: require.resolve("css-loader"), + options: { + importLoaders: 1, + }, + }, + { + loader: require.resolve("sass-loader") + } + ], + }, // "file" loader makes sure those assets get served by WebpackDevServer. // When you `import` an asset, you get its (virtual) filename. // In production, they would get copied to the `build` folder. diff --git a/public/react/config/webpack.config.prod.js b/public/react/config/webpack.config.prod.js index ddc111b9c..e97483c0e 100644 --- a/public/react/config/webpack.config.prod.js +++ b/public/react/config/webpack.config.prod.js @@ -224,6 +224,23 @@ module.exports = { ), // Note: this won't work without `new ExtractTextPlugin()` in `plugins`. }, + { + test: /\.scss$/, + use: [ + require.resolve("style-loader"), + { + loader: require.resolve("css-loader"), + options: { + importLoaders: 1, + minimize: true, + sourceMap: shouldUseSourceMap, + }, + }, + { + loader: require.resolve("sass-loader") + } + ], + }, // "file" loader makes sure assets end up in the `build` folder. // When you `import` an asset, you get its filename. // This loader doesn't use a "test" so it will catch all modules diff --git a/public/react/package.json b/public/react/package.json index 84dec6d11..8d7362c28 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -163,6 +163,8 @@ "babel-plugin-import": "^1.11.0", "concat": "^1.0.3", "happypack": "^5.0.1", + "node-sass": "^4.12.0", + "sass-loader": "^7.3.1", "webpack-bundle-analyzer": "^3.0.3", "webpack-parallel-uglify-plugin": "^1.1.0" } diff --git a/public/react/src/App.js b/public/react/src/App.js index 1a4aedc05..6b7a74cd4 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -262,6 +262,11 @@ const Help = Loadable({ loading: Loading, }) +const EcsHome = Loadable({ + loader: () => import('./modules/ecs/Home'), + loading: Loading, +}) + class App extends Component { constructor(props) { super(props) @@ -516,6 +521,10 @@ class App extends Component { render={ (props)=>() }/> + () + }/> diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 9653eb690..099b9ddc0 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -50,7 +50,7 @@ export function initAxiosInterceptors(props) { // wy // proxy="http://192.168.2.63:3001" - + proxy = "http://localhost:3001" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 const requestMap = {}; diff --git a/public/react/src/images/ecs/bg.jpg b/public/react/src/images/ecs/bg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2abdb6a7cc4a9428a03cd6ae529377f1a427e0a GIT binary patch literal 81209 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

i?3b2 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 selected && 已选择 }, +]; +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(); + } + } + + 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){ + const 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 ( +

+ + +
+ this.setState({keyword: e.target.value})} + onSearch={this.getMajors} + value={keyword}/> +
+ +
+ +
{ this.state.error }
+ + + + ) + } +} + +AddMajorModal.propTypes = { + schoolId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddMajorModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddMajorModal.scss b/public/react/src/modules/ecs/Home/AddMajorModal.scss new file mode 100644 index 000000000..f79576eab --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddMajorModal.scss @@ -0,0 +1,28 @@ +.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 { + text-align: center; + border-top: unset; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.js b/public/react/src/modules/ecs/Home/AddManagerModal.js new file mode 100644 index 000000000..99dc6cd8e --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddManagerModal.js @@ -0,0 +1,220 @@ +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) =>
{text}
+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); + } + + 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){ + const 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 ( +
+ + +
+
+ +
+ + + + + + + + + + + + + + this.setState({ school: e.target.value })} value={school} placeholder="请输入学校名称"/> + + + + + + + + + +
+
+
{ this.state.error }
+ + + + ) + } +} + +AddManagerModal.propTypes = { + schoolId: PropTypes.string, + schoolName: PropTypes.string, + majorId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddManagerModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.scss b/public/react/src/modules/ecs/Home/AddManagerModal.scss new file mode 100644 index 000000000..b3c39f1f4 --- /dev/null +++ b/public/react/src/modules/ecs/Home/AddManagerModal.scss @@ -0,0 +1,34 @@ +.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 { + text-align: center; + border-top: unset; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/MajorManager.js b/public/react/src/modules/ecs/Home/MajorManager.js new file mode 100644 index 000000000..37b9d6e49 --- /dev/null +++ b/public/react/src/modules/ecs/Home/MajorManager.js @@ -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 ( +
+ { + managers && managers.map(manager => { + return ( + { this.deleteManager(manager.id) }} color="blue"> + { manager.name } + + ) + }) + } +
+ ) + } +} + +MajorManager.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.number, + canManage: PropTypes.bool, + managers: PropTypes.array +} + +export default MajorManager \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/index.js b/public/react/src/modules/ecs/Home/index.js new file mode 100644 index 000000000..30fbf64f5 --- /dev/null +++ b/public/react/src/modules/ecs/Home/index.js @@ -0,0 +1,268 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import { Spin, Avatar, Tooltip, Button, Divider, Input, Row, Col, Icon, Modal } from "antd"; +import { SnackbarHOC, getImageUrl } from 'educoder'; +import axios from 'axios'; + +import './index.scss'; +import bgImage from '../../../images/ecs/bg.jpg'; + +import {TPMIndexHOC} from "../../tpm/TPMIndexHOC"; +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() { + window.document.title = "专业列表"; + this.getSchoolDetail(); + } + + getSchoolDetail() { + axios.get(`/schools/${this.state.schoolId}/detail.json`).then(result => { + if(result.status === 200){ + 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.state.searchKeyword = ''; + this.getSchoolMajors(); + } + } + HideAddManagerModal(added){ + this.setState({ AddManagerVisible: false }); + if(added){ + this.state.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 ( +
+ +
+
+
+ { school && school.name } +
+
+ +
+
+
学校管理员
+
温馨提醒:学校管理员有添加专业及设置专业管理员等权限
+
+
+ { + managers && managers.map((manager) => { + return ( + + + + { manager.name } + + + ) + }) + } +
+
+ +
+
+
+
专业列表
+
+ 请添加参与认证的专业名称 + 查看详情 +
+
+ +
+ + + +
+
+
{majorCount || 0} 个检索结果({majorCount || 0} 专业)
+ this.setState({searchKeyword: e.target.value})} + onSearch={this.getSchoolMajors} + value={this.state.searchKeyword} + style={{ width: 200 }} + /> +
+
+ +
序号 + 专业代码 + 专业名称 + 专业管理员 + 操作 + + + { + templateMajor && ( + + 0 + 000000 + + { templateMajor.name } + + + + { configBtnText } + + + ) + } + { + majors && majors.map((major, index) => { + return ( + + { index + 1 } + { major.code } + + { major.name } + + +
+ { manageMajor && this.showAddManagerModal(major.id)}> } + + +
+ + + { configBtnText } + { manageSchool && ( this.showDeleteMajorConfirm(major.id)}>删除 ) } + + + ) + }) + } + + + + + + + + { this.state.school && } + + + ) + } +} + +export default SnackbarHOC() (TPMIndexHOC ( Home )); \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/index.scss b/public/react/src/modules/ecs/Home/index.scss new file mode 100644 index 000000000..93a5d3f35 --- /dev/null +++ b/public/react/src/modules/ecs/Home/index.scss @@ -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; + } +} \ No newline at end of file diff --git a/public/react/src/modules/help/Help.js b/public/react/src/modules/help/Help.js index f04079bcc..f148dd373 100644 --- a/public/react/src/modules/help/Help.js +++ b/public/react/src/modules/help/Help.js @@ -26,7 +26,6 @@ class Help extends React.Component { } componentDidUpdate(prevProps) { - console.log('update', prevProps, this.props); if(prevProps.match.params.type !== this.props.match.params.type){ this.setState({ type: this.props.match.params.type }); } From ac67cdafadd30e703cecf86e8af8ec3725a5fcd4 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 12 Sep 2019 09:35:39 +0800 Subject: [PATCH 02/23] ecs: ec year list page --- .../ecs/ec_major_schools_controller.rb | 13 ++ app/controllers/ecs/ec_years_controller.rb | 4 +- app/helpers/ecs/ec_years_helper.rb | 22 ++ app/models/ec_course_support.rb | 1 - app/models/ec_major_school.rb | 2 + app/models/ec_year.rb | 4 + app/services/ecs/copy_ec_year_service.rb | 2 +- .../ecs/ec_major_schools/show.json.jbuilder | 6 + app/views/ecs/ec_years/index.json.jbuilder | 13 +- config/routes.rb | 2 +- ...0190911080150_change_ec_course_supports.rb | 11 + public/react/src/App.js | 8 +- public/react/src/AppConfig.js | 1 - .../src/modules/ecs/EcYear/AddYearModal.js | 108 +++++++++ .../src/modules/ecs/EcYear/AddYearModal.scss | 34 +++ public/react/src/modules/ecs/EcYear/index.js | 207 ++++++++++++++++++ .../react/src/modules/ecs/EcYear/index.scss | 56 +++++ public/react/src/modules/ecs/Ecs.js | 25 +++ .../src/modules/ecs/Home/AddMajorModal.js | 10 +- .../src/modules/ecs/Home/AddMajorModal.scss | 1 + .../src/modules/ecs/Home/AddManagerModal.js | 10 +- .../src/modules/ecs/Home/AddManagerModal.scss | 1 + public/react/src/modules/ecs/Home/index.js | 17 +- 23 files changed, 532 insertions(+), 26 deletions(-) create mode 100644 app/helpers/ecs/ec_years_helper.rb create mode 100644 app/views/ecs/ec_major_schools/show.json.jbuilder create mode 100644 db/migrate/20190911080150_change_ec_course_supports.rb create mode 100644 public/react/src/modules/ecs/EcYear/AddYearModal.js create mode 100644 public/react/src/modules/ecs/EcYear/AddYearModal.scss create mode 100644 public/react/src/modules/ecs/EcYear/index.js create mode 100644 public/react/src/modules/ecs/EcYear/index.scss create mode 100644 public/react/src/modules/ecs/Ecs.js diff --git a/app/controllers/ecs/ec_major_schools_controller.rb b/app/controllers/ecs/ec_major_schools_controller.rb index b7af447e2..c5f187af0 100644 --- a/app/controllers/ecs/ec_major_schools_controller.rb +++ b/app/controllers/ecs/ec_major_schools_controller.rb @@ -1,4 +1,6 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController + skip_before_action :check_user_permission!, only: [:show] + def index major_schools = current_school.ec_major_schools.not_template @@ -23,6 +25,17 @@ class Ecs::EcMajorSchoolsController < Ecs::BaseController @template_major_school = EcMajorSchool.is_template.first #示例专业 end + # :show是 /api/ec_major_schools/:id + def show + @major = EcMajorSchool.find(params[:id]) + school = @major.school + + return if current_user.admin? || school.manager?(current_user) + return if @major.manager?(current_user) + + render_forbidden + end + def create ActiveRecord::Base.transaction do Array(params[:major_ids].presence).each do |id| diff --git a/app/controllers/ecs/ec_years_controller.rb b/app/controllers/ecs/ec_years_controller.rb index 2257911a7..896aaed8a 100644 --- a/app/controllers/ecs/ec_years_controller.rb +++ b/app/controllers/ecs/ec_years_controller.rb @@ -10,7 +10,7 @@ class Ecs::EcYearsController < Ecs::BaseController end @count = ec_years.count - @ec_years = paginate ec_years + @ec_years = paginate ec_years.order(year: :desc) return if @ec_years.blank? @@ -33,7 +33,7 @@ class Ecs::EcYearsController < Ecs::BaseController return end - @ec_year = CopyEcYearService.call(current_major_school, params[:year].to_i) + @ec_year = Ecs::CopyEcYearService.call(current_major_school, params[:year].to_i) end def destroy diff --git a/app/helpers/ecs/ec_years_helper.rb b/app/helpers/ecs/ec_years_helper.rb new file mode 100644 index 000000000..108abb0e7 --- /dev/null +++ b/app/helpers/ecs/ec_years_helper.rb @@ -0,0 +1,22 @@ +module Ecs::EcYearsHelper + def achieved_graduation_course_count(ec_year) + return 0 if ec_year.ec_courses.count.zero? + + course_ids = ec_year.ec_courses.map(&:id) + target_count_map = EcCourseTarget.where(ec_course_id: course_ids).group(:ec_course_id).count + + ec_year.ec_courses.sum { |course| course.complete_target_count == target_count_map[course.id] ? 1 : 0 } + end + + def achieved_graduation_objective_count(ec_year) + return 0 if ec_year.ec_graduation_subitems.count.zero? + + subitem_ids = ec_year.ec_graduation_subitems.reorder(nil).pluck(:id) + + relations = EcGraduationRequirementCalculation.joins(:ec_course_support).where(ec_course_supports: { ec_graduation_subitem_id: subitem_ids }) + + reached_map = relations.where(status: true).group('ec_graduation_subitem_id').count + + reached_map.keys.size + end +end \ No newline at end of file diff --git a/app/models/ec_course_support.rb b/app/models/ec_course_support.rb index a6ca96ea9..c7865f73c 100644 --- a/app/models/ec_course_support.rb +++ b/app/models/ec_course_support.rb @@ -3,7 +3,6 @@ class EcCourseSupport < ApplicationRecord belongs_to :ec_course belongs_to :ec_graduation_subitem - # TODO: 将 ec_graduation_subitem_courses 移除,这个表作为关系表 has_one :ec_graduation_requirement_calculation, dependent: :destroy diff --git a/app/models/ec_major_school.rb b/app/models/ec_major_school.rb index 41a835f63..5cfc4df9e 100644 --- a/app/models/ec_major_school.rb +++ b/app/models/ec_major_school.rb @@ -12,6 +12,8 @@ class EcMajorSchool < ApplicationRecord scope :is_template, -> { where(template_major: true) } scope :not_template, -> { where(template_major: false) } + delegate :code, :name, to: :ec_major + # 是否为该专业管理员 def manager?(user) ec_major_school_users.exists?(user_id: user.id) diff --git a/app/models/ec_year.rb b/app/models/ec_year.rb index 153edcf16..6a3d97340 100644 --- a/app/models/ec_year.rb +++ b/app/models/ec_year.rb @@ -12,4 +12,8 @@ class EcYear < ApplicationRecord has_many :ec_course_users, dependent: :destroy has_many :managers, through: :ec_course_users, source: :user + + def prev_year + self.class.find_by(year: year.to_i - 1) + end end diff --git a/app/services/ecs/copy_ec_year_service.rb b/app/services/ecs/copy_ec_year_service.rb index 87cbe0845..462681eba 100644 --- a/app/services/ecs/copy_ec_year_service.rb +++ b/app/services/ecs/copy_ec_year_service.rb @@ -1,4 +1,4 @@ -class CopyEcYearService < ApplicationService +class Ecs::CopyEcYearService < ApplicationService attr_reader :major_school, :to_year def initialize(major_school, year) diff --git a/app/views/ecs/ec_major_schools/show.json.jbuilder b/app/views/ecs/ec_major_schools/show.json.jbuilder new file mode 100644 index 000000000..7c911d824 --- /dev/null +++ b/app/views/ecs/ec_major_schools/show.json.jbuilder @@ -0,0 +1,6 @@ +json.extract! @major, :id, :code, :name, :template_major +json.school_id @major.school.id +json.school_name @major.school.name + +can_manager = @major.manager?(current_user) || @major.school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/app/views/ecs/ec_years/index.json.jbuilder b/app/views/ecs/ec_years/index.json.jbuilder index c5c89cd06..b0a8985b2 100644 --- a/app/views/ecs/ec_years/index.json.jbuilder +++ b/app/views/ecs/ec_years/index.json.jbuilder @@ -8,7 +8,16 @@ json.ec_years do json.training_subitem_count @training_subitem_count_map.fetch(ec_year.id, 0) json.graduation_requirement_count @graduation_requirement_count_map.fetch(ec_year.id, 0) json.course_count @course_count_map.fetch(ec_year.id, 0) - json.course_target_count @course_target_count_map.fetch(ec_year.id, 0) - json.graduation_subitem_count @graduation_subitem_count_map.fetch(ec_year.id, 0) + + course_target = @course_target_count_map.fetch(ec_year.id, 0) + graduation_subitem = @graduation_subitem_count_map.fetch(ec_year.id, 0) + achieved_course = achieved_graduation_course_count(ec_year) + achieved_objective = achieved_graduation_objective_count(ec_year) + + json.course_target_count course_target + json.graduation_subitem_count graduation_subitem + json.achieved_graduation_course_count achieved_course + json.achieved_graduation_objective_count achieved_objective + json.status graduation_subitem == achieved_objective ? 'achieved' : 'not_achieved' end end \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index d043eff96..e1e139c9d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -707,7 +707,7 @@ Rails.application.routes.draw do # 为避免url过长以及层级过深,路由定义和controller继承都做了处理 scope module: :ecs do - resources :ec_major_schools, only: [] do + resources :ec_major_schools, only: [:show] do resources :users, only: [:index] resources :major_managers, only: [:create, :destroy] resources :ec_years, only: [:index, :create, :destroy] diff --git a/db/migrate/20190911080150_change_ec_course_supports.rb b/db/migrate/20190911080150_change_ec_course_supports.rb new file mode 100644 index 000000000..07c3a536d --- /dev/null +++ b/db/migrate/20190911080150_change_ec_course_supports.rb @@ -0,0 +1,11 @@ +class ChangeEcCourseSupports < ActiveRecord::Migration[5.2] + def change + add_column :ec_course_supports, :ec_graduation_subitem_id, :integer, index: true + + execute <<-SQL + UPDATE ec_course_supports ecs SET ec_graduation_subitem_id = ( + SELECT ec_graduation_subitem_id FROM ec_graduation_subitem_courses egsc WHERE egsc.ec_course_support_id = ecs.id + ) + SQL + end +end diff --git a/public/react/src/App.js b/public/react/src/App.js index 6b7a74cd4..ddb8de809 100644 --- a/public/react/src/App.js +++ b/public/react/src/App.js @@ -262,8 +262,8 @@ const Help = Loadable({ loading: Loading, }) -const EcsHome = Loadable({ - loader: () => import('./modules/ecs/Home'), +const Ecs = Loadable({ + loader: () => import('./modules/ecs/Ecs'), loading: Loading, }) @@ -521,9 +521,9 @@ class App extends Component { render={ (props)=>() }/> - () + (props)=>() }/> diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 099b9ddc0..5d2373e84 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -50,7 +50,6 @@ export function initAxiosInterceptors(props) { // wy // proxy="http://192.168.2.63:3001" - proxy = "http://localhost:3001" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 const requestMap = {}; diff --git a/public/react/src/modules/ecs/EcYear/AddYearModal.js b/public/react/src/modules/ecs/EcYear/AddYearModal.js new file mode 100644 index 000000000..9e91e34ec --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/AddYearModal.js @@ -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 ( +
+ + +
+
+ 基础数据:除学生列表与成绩录入以外的所有基础数据
+ 将自动复制上届别的数据;数据均可再编辑 +
+ +
+
选择届别:
+
+ +
+
+
+
+
+ ) + } +} + +AddYearModal.propTypes = { + schoolId: PropTypes.number, + majorId: PropTypes.number, + visible: PropTypes.bool, + onHide: PropTypes.func +} + +export default AddYearModal \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/AddYearModal.scss b/public/react/src/modules/ecs/EcYear/AddYearModal.scss new file mode 100644 index 000000000..75218677d --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/AddYearModal.scss @@ -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; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/index.js b/public/react/src/modules/ecs/EcYear/index.js new file mode 100644 index 000000000..bb3b3bfe0 --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/index.js @@ -0,0 +1,207 @@ +import React from 'react'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import { Spin, Button, Table, Input, Divider, Modal, message } 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 { num === 0 ? "立即配置" : num }; + } + const contrastRender = (num, other) => { + let color = other !== 0 && num === other ? 'color-green' : 'color-orange'; + + return other === 0 ? ( +
-- / --
+ ) : ( +
{num} / {other}
+ ) + } + const statusRender = (text, record) => { + let zero = record.graduation_subitem_count === 0; + + return zero ? ( + -- + ) : ( + + { text === 'achieved' ? '已达成' : '未达成' } + + ) + } + const operationRender = (_, record) => { + return ( + + ) + } + const tableColumns = [ + { title: '届别', dataIndex: 'year', render: text => `${text}届` }, + { title: '培养目标', dataIndex: 'training_subitem_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_years/${record.id}/training_objectives`), }, + { title: '毕业要求', dataIndex: 'graduation_requirement_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_years/${record.id}/graduation_requirement`), }, + { title: '课程体系', dataIndex: 'course_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_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 ( +
+ +
+
+
+
{ major.name }
+
+ 请选择添加参与认证的学生界别,多个界别分次添加 + 查看详情 +
+
+ +
+ + + +
+
+ this.setState({keyword: e.target.value})} + onSearch={this.onSearch} + value={keyword} + style={{ width: 200 }}/> +
+ +
+
+ + + + + + + + ) + } +} + +export default EcYear; \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/index.scss b/public/react/src/modules/ecs/EcYear/index.scss new file mode 100644 index 000000000..a0b96541d --- /dev/null +++ b/public/react/src/modules/ecs/EcYear/index.scss @@ -0,0 +1,56 @@ +.ec-year-list-page { + background: #fff; + + .year-list { + &-head { + margin-top: 30px; + 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; + } + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/Ecs.js b/public/react/src/modules/ecs/Ecs.js new file mode 100644 index 000000000..307754e61 --- /dev/null +++ b/public/react/src/modules/ecs/Ecs.js @@ -0,0 +1,25 @@ +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')); + +class Ecs extends React.Component { + + render() { + return ( +
+ + + + +
+ ) + } +} + +export default SnackbarHOC() (TPMIndexHOC ( Ecs )); \ No newline at end of file diff --git a/public/react/src/modules/ecs/Home/AddMajorModal.js b/public/react/src/modules/ecs/Home/AddMajorModal.js index f1282e244..9b58ed7e4 100644 --- a/public/react/src/modules/ecs/Home/AddMajorModal.js +++ b/public/react/src/modules/ecs/Home/AddMajorModal.js @@ -43,6 +43,12 @@ class AddMajorModal extends React.Component { } } + onSearch = () => { + this.setState({ pagination: {...defaultPagination} }, () => { + this.getMajors(); + }) + } + getMajors(){ let { schoolId, keyword, pagination } = this.state; @@ -55,7 +61,7 @@ class AddMajorModal extends React.Component { } }).then(res => { if(res.status === 200){ - const pagination = { ...this.state.pagination }; + let pagination = { ...this.state.pagination }; pagination.total = res.data.count; this.setState({ @@ -143,7 +149,7 @@ class AddMajorModal extends React.Component { this.setState({keyword: e.target.value})} - onSearch={this.getMajors} + onSearch={this.onSearch} value={keyword}/> diff --git a/public/react/src/modules/ecs/Home/AddMajorModal.scss b/public/react/src/modules/ecs/Home/AddMajorModal.scss index f79576eab..bde678bcd 100644 --- a/public/react/src/modules/ecs/Home/AddMajorModal.scss +++ b/public/react/src/modules/ecs/Home/AddMajorModal.scss @@ -22,6 +22,7 @@ } } .ant-modal-footer { + padding-bottom: 20px; text-align: center; border-top: unset; } diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.js b/public/react/src/modules/ecs/Home/AddManagerModal.js index 99dc6cd8e..7e341ea11 100644 --- a/public/react/src/modules/ecs/Home/AddManagerModal.js +++ b/public/react/src/modules/ecs/Home/AddManagerModal.js @@ -43,6 +43,12 @@ class AddManagerModal extends React.Component { 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; @@ -61,7 +67,7 @@ class AddManagerModal extends React.Component { } }).then(res => { if(res.status === 200){ - const pagination = { ...this.state.pagination }; + let pagination = { ...this.state.pagination }; pagination.total = res.data.count; this.setState({ @@ -186,7 +192,7 @@ class AddManagerModal extends React.Component {
- + diff --git a/public/react/src/modules/ecs/Home/AddManagerModal.scss b/public/react/src/modules/ecs/Home/AddManagerModal.scss index b3c39f1f4..2b30690fc 100644 --- a/public/react/src/modules/ecs/Home/AddManagerModal.scss +++ b/public/react/src/modules/ecs/Home/AddManagerModal.scss @@ -28,6 +28,7 @@ } } .ant-modal-footer { + padding-bottom: 20px; text-align: center; border-top: unset; } diff --git a/public/react/src/modules/ecs/Home/index.js b/public/react/src/modules/ecs/Home/index.js index 30fbf64f5..8f66b6572 100644 --- a/public/react/src/modules/ecs/Home/index.js +++ b/public/react/src/modules/ecs/Home/index.js @@ -1,13 +1,12 @@ import React from 'react'; import { Link } from 'react-router-dom'; import { Spin, Avatar, Tooltip, Button, Divider, Input, Row, Col, Icon, Modal } from "antd"; -import { SnackbarHOC, getImageUrl } from 'educoder'; +import { getImageUrl } from 'educoder'; import axios from 'axios'; import './index.scss'; import bgImage from '../../../images/ecs/bg.jpg'; -import {TPMIndexHOC} from "../../tpm/TPMIndexHOC"; import MajorManager from "./MajorManager"; import AddMajorModal from "./AddMajorModal"; import AddManagerModal from "./AddManagerModal"; @@ -52,13 +51,13 @@ class Home extends React.Component { } componentDidMount() { - window.document.title = "专业列表"; 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, @@ -100,15 +99,13 @@ class Home extends React.Component { HideAddMajorModal(added){ this.setState({ AddMajorVisible: false }); if(added){ - this.state.searchKeyword = ''; - this.getSchoolMajors(); + this.setState({ searchKeyword: '' }, this.getSchoolMajors) } } HideAddManagerModal(added){ this.setState({ AddManagerVisible: false }); if(added){ - this.state.searchKeyword = ''; - this.getSchoolMajors(); + this.setState({ searchKeyword: '' }, this.getSchoolMajors) } } @@ -219,7 +216,7 @@ class Home extends React.Component { - { configBtnText } + { configBtnText } ) @@ -244,7 +241,7 @@ class Home extends React.Component { - { configBtnText } + { configBtnText } { manageSchool && ( this.showDeleteMajorConfirm(major.id)}>删除 ) } @@ -265,4 +262,4 @@ class Home extends React.Component { } } -export default SnackbarHOC() (TPMIndexHOC ( Home )); \ No newline at end of file +export default Home; \ No newline at end of file From 0ed5b1d79f39ba522a43c164a6a5cc4a3b1b0176 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Mon, 16 Sep 2019 15:49:07 +0800 Subject: [PATCH 03/23] ecs: training_objectives page --- .../ecs/ec_training_objectives_controller.rb | 2 +- app/controllers/ecs/ec_years_controller.rb | 4 + app/models/ec_training_subitem.rb | 2 + .../ecs/create_training_objective_service.rb | 17 +- .../_ec_training_objective.json.jbuilder | 2 +- .../ec_training_objectives/show.json.jbuilder | 2 +- .../ec_training_objectives/show.xlsx.axlsx | 6 +- app/views/ecs/ec_years/show.json.jbuilder | 13 + config/routes.rb | 2 +- .../EcSetting/GraduationRequirement/index.js | 72 +++++ .../GraduationRequirement/index.scss | 0 .../ecs/EcSetting/TrainingObjective/index.js | 264 ++++++++++++++++++ .../EcSetting/TrainingObjective/index.scss | 99 +++++++ .../react/src/modules/ecs/EcSetting/index.js | 110 ++++++++ .../src/modules/ecs/EcSetting/index.scss | 62 ++++ .../src/modules/ecs/EcYear/AddYearModal.js | 2 +- public/react/src/modules/ecs/EcYear/index.js | 75 ++--- .../react/src/modules/ecs/EcYear/index.scss | 10 +- public/react/src/modules/ecs/Ecs.js | 2 + 19 files changed, 697 insertions(+), 49 deletions(-) create mode 100644 app/views/ecs/ec_years/show.json.jbuilder create mode 100644 public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js create mode 100644 public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss create mode 100644 public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js create mode 100644 public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss create mode 100644 public/react/src/modules/ecs/EcSetting/index.js create mode 100644 public/react/src/modules/ecs/EcSetting/index.scss diff --git a/app/controllers/ecs/ec_training_objectives_controller.rb b/app/controllers/ecs/ec_training_objectives_controller.rb index 318faa6ff..79b232822 100644 --- a/app/controllers/ecs/ec_training_objectives_controller.rb +++ b/app/controllers/ecs/ec_training_objectives_controller.rb @@ -2,7 +2,7 @@ class Ecs::EcTrainingObjectivesController < Ecs::BaseController before_action :check_major_manager_permission!, only: [:create] def show - @training_objective = current_year.ec_training_objective + @training_objective = current_year.ec_training_objective || current_year.build_ec_training_objective respond_to do |format| format.json diff --git a/app/controllers/ecs/ec_years_controller.rb b/app/controllers/ecs/ec_years_controller.rb index 896aaed8a..9764e451d 100644 --- a/app/controllers/ecs/ec_years_controller.rb +++ b/app/controllers/ecs/ec_years_controller.rb @@ -27,6 +27,10 @@ class Ecs::EcYearsController < Ecs::BaseController .where(ec_graduation_requirements: { ec_year_id: year_ids }).group('ec_year_id').count end + def show + @year = current_year + end + def create if current_major_school.ec_years.exists?(year: params[:year].to_i) render_error('届别已存在') diff --git a/app/models/ec_training_subitem.rb b/app/models/ec_training_subitem.rb index 0c9c61fbc..736e3f0da 100644 --- a/app/models/ec_training_subitem.rb +++ b/app/models/ec_training_subitem.rb @@ -1,4 +1,6 @@ class EcTrainingSubitem < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_training_objective has_many :ec_requirement_vs_objectives, foreign_key: :ec_training_objective_id, dependent: :destroy diff --git a/app/services/ecs/create_training_objective_service.rb b/app/services/ecs/create_training_objective_service.rb index c3dc3c8a6..effbf5420 100644 --- a/app/services/ecs/create_training_objective_service.rb +++ b/app/services/ecs/create_training_objective_service.rb @@ -11,13 +11,16 @@ class Ecs::CreateTrainingObjectiveService < ApplicationService def call training_objective.content = params[:content].to_s.strip - attributes = build_accepts_nested_attributes( - training_objective, - training_objective.ec_training_subitems, - params[:training_subitems], - &method(:training_subitem_param_handler) - ) - training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + if params.key?(:training_subitems) + attributes = build_accepts_nested_attributes( + training_objective, + training_objective.ec_training_subitems, + params[:training_subitems], + &method(:training_subitem_param_handler) + ) + attributes.each_with_index { |attr, index| attr[:position] = index + 1 } + training_objective.assign_attributes(ec_training_subitems_attributes: attributes) + end training_objective.save! training_objective diff --git a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder index 83414d2f4..61992d8e1 100644 --- a/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/shared/_ec_training_objective.json.jbuilder @@ -1,3 +1,3 @@ json.extract! ec_training_objective, :id, :content -json.ec_training_items ec_training_objective.ec_training_subitems, partial: 'ec_training_subitem', as: :ec_training_subitem +json.ec_training_items ec_training_objective.ec_training_subitems, partial: '/ecs/ec_training_objectives/shared/ec_training_subitem', as: :ec_training_subitem diff --git a/app/views/ecs/ec_training_objectives/show.json.jbuilder b/app/views/ecs/ec_training_objectives/show.json.jbuilder index a37fa1c09..00825be4c 100644 --- a/app/views/ecs/ec_training_objectives/show.json.jbuilder +++ b/app/views/ecs/ec_training_objectives/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_training_objective', ec_training_objective: @training_objective +json.partial! '/ecs/ec_training_objectives/shared/ec_training_objective', ec_training_objective: @training_objective diff --git a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx index 4746be0ea..130e80e6b 100644 --- a/app/views/ecs/ec_training_objectives/show.xlsx.axlsx +++ b/app/views/ecs/ec_training_objectives/show.xlsx.axlsx @@ -6,11 +6,11 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', border: { style: :thin, color: '000000' }, alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '培养目标及目标分解') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['培养目标及目标分解'], style: title_style sheet.add_row [] sheet.add_row [] @@ -27,6 +27,6 @@ wb.styles do |style| end items_size = training_objective.ec_training_subitems.size - sheet.merge_cells("A9:A#{9 + items_size}") + sheet.merge_cells("A9:A#{9 + items_size - 1}") end end \ No newline at end of file diff --git a/app/views/ecs/ec_years/show.json.jbuilder b/app/views/ecs/ec_years/show.json.jbuilder new file mode 100644 index 000000000..ba8333086 --- /dev/null +++ b/app/views/ecs/ec_years/show.json.jbuilder @@ -0,0 +1,13 @@ +json.extract! @year, :id, :year + +major = @year.ec_major_school +json.major_id major.id +json.major_name major.name +json.major_code major.code + +school = major.school +json.school_id school.id +json.school_name school.name + +can_manager = major.manager?(current_user) || school.manager?(current_user) || current_user.admin_or_business? +json.can_manager can_manager \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index e1e139c9d..8098d03c9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -710,7 +710,7 @@ Rails.application.routes.draw do resources :ec_major_schools, only: [:show] do resources :users, only: [:index] resources :major_managers, only: [:create, :destroy] - resources :ec_years, only: [:index, :create, :destroy] + resources :ec_years, only: [:index, :show, :create, :destroy] end resources :ec_years, only: [] do diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js new file mode 100644 index 000000000..ea46b2604 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js @@ -0,0 +1,72 @@ +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 GraduationRequirement extends React.Component { + constructor (props) { + super(props); + + this.state = { + loading: true, + + graduationRequirements: [] + } + } + + componentDidMount() { + this.getData(); + } + + getData = () => { + let { yearId } = this.props; + + axios.get(`/ec_years/${yearId}/ec_graduation_requirements.json`).then(res => { + if(res.status === 200){ + this.setState({ + graduationRequirements: res.data.ec_graduation_requirements, + loading: false + }) + } + }).catch(e => console.log(e)) + } + + render() { + let { can_manager } = this.props.year; + let { loading } = this.state; + + return ( +
+ +
+
+
+
毕业要求(及其指标点)
+
+ 请结合本专业特色修改毕业要求文字描述及指标点,需完全覆盖12项通用标准 + 查看详情 +
+
+ 导出毕业要求 +
+ + + +
+
+
+
+
+ ) + } +} +GraduationRequirement.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.string, + yearId: PropTypes.string, +} + +export default GraduationRequirement \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss new file mode 100644 index 000000000..e69de29bb diff --git a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js new file mode 100644 index 000000000..859b987ee --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js @@ -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 ( +
+ +
+
+
+
培养目标
+
+ 请结合本专业特色修改培养目标文字描述及目标分解查看详情 + 查看详情 +
+
+ 导出培养目标 +
+ + + +
+ { + can_manager && contentEditState ? ( +
+
+ + this.setState({ editContent: e.target.value })} /> + +
+
+ + +
+
+ ) : ( +
+
{ objective.content }
+ { + can_manager && ( +
+ + this.setState({ contentEditState: true })} /> + +
+ ) + } +
+ ) + } + +
+
+
分项
+
目标分解详情
+
+ { + itemsEditState || ( + + + + ) + } +
+
+
+ { + can_manager && itemsEditState ? ( +
+ { + trainingSubitems && trainingSubitems.map((item, index) => { + return ( +
+
{index + 1}
+
+ + this.onItemContentChange(e, index)} /> + +
+ { index !== 0 && this.removeItemColumn(index)} /> } + + this.addItemColumn(index + 1)} style={{ color: '#29BD8B' }} /> +
+
+
+ ) + }) + } + +
+ + +
+
+ ) : ( + objective.ec_training_items && objective.ec_training_items.map((item, index) => { + return ( +
+
{ index + 1 }
+
{ item.content }
+
+ ) + }) + ) + } +
+
+
+
+
+
+ ) + } +} +TrainingObjective.propTypes = { + schoolId: PropTypes.string, + majorId: PropTypes.string, + yearId: PropTypes.string, +} + +export default TrainingObjective \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss new file mode 100644 index 000000000..50b801459 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.scss @@ -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; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js new file mode 100644 index 000000000..238d8474c --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -0,0 +1,110 @@ +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"; + +const { Step } = Steps; + +const TrainingObjective = CustomLoadable(() => import('./TrainingObjective/index')) + +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"]; + +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 }); + 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 ( +
+
+
+ + + { year && year.school_name } + + + { year && year.major_name } + + {year && year.year}届 + +
+ +
+ + + { + steps.map((title, index) => { + return ( + + ) + }) + } + +
+ + { + year && ( + + () }> + + ) + } +
+
+ ) + } +} + +export default EcSetting \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/index.scss b/public/react/src/modules/ecs/EcSetting/index.scss new file mode 100644 index 000000000..8c8d7cbd3 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/index.scss @@ -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; + + &-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; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcYear/AddYearModal.js b/public/react/src/modules/ecs/EcYear/AddYearModal.js index 9e91e34ec..e54ba6b73 100644 --- a/public/react/src/modules/ecs/EcYear/AddYearModal.js +++ b/public/react/src/modules/ecs/EcYear/AddYearModal.js @@ -70,7 +70,7 @@ class AddYearModal extends React.Component { onOk={this.handleOk} onCancel={this.handleCancel}> -
+
基础数据:除学生列表与成绩录入以外的所有基础数据
将自动复制上届别的数据;数据均可再编辑 diff --git a/public/react/src/modules/ecs/EcYear/index.js b/public/react/src/modules/ecs/EcYear/index.js index bb3b3bfe0..e9d3a0296 100644 --- a/public/react/src/modules/ecs/EcYear/index.js +++ b/public/react/src/modules/ecs/EcYear/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { Link } from 'react-router-dom'; import axios from 'axios'; -import { Spin, Button, Table, Input, Divider, Modal, message } from 'antd'; +import { Spin, Button, Table, Input, Divider, Modal, message, Breadcrumb } from 'antd'; import './index.scss'; import AddYearModal from "./AddYearModal"; @@ -141,16 +141,16 @@ class EcYear extends React.Component { const operationRender = (_, record) => { return (
- 立即配置 + 立即配置 this.showDeleteYearConfirm(record.id)}>删除
) } const tableColumns = [ { title: '届别', dataIndex: 'year', render: text => `${text}届` }, - { title: '培养目标', dataIndex: 'training_subitem_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_years/${record.id}/training_objectives`), }, - { title: '毕业要求', dataIndex: 'graduation_requirement_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_years/${record.id}/graduation_requirement`), }, - { title: '课程体系', dataIndex: 'course_count', render: (text, record) => linkRender(text, `/ecs/major_schools/${this.state.majorId}/academic_years/${record.id}/ec_course_setting`), }, + { 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 }, @@ -161,35 +161,46 @@ class EcYear extends React.Component {
-
-
-
{ major.name }
-
- 请选择添加参与认证的学生界别,多个界别分次添加 - 查看详情 -
-
- +
+ + + { major && major.school_name } + + { major && major.name } +
- - - -
-
- this.setState({keyword: e.target.value})} - onSearch={this.onSearch} - value={keyword} - style={{ width: 200 }}/> + +
+
+
+
{ major.name }
+
+ 请选择添加参与认证的学生界别,多个界别分次添加 + 查看详情 +
+
+
- -
-
+ + + +
+
+ this.setState({keyword: e.target.value})} + onSearch={this.onSearch} + value={keyword} + style={{ width: 200 }}/> +
+ +
+
+ diff --git a/public/react/src/modules/ecs/EcYear/index.scss b/public/react/src/modules/ecs/EcYear/index.scss index a0b96541d..66f49e304 100644 --- a/public/react/src/modules/ecs/EcYear/index.scss +++ b/public/react/src/modules/ecs/EcYear/index.scss @@ -1,9 +1,15 @@ .ec-year-list-page { - background: #fff; + .ec-breadcrumb { + margin-top: 10px; + margin-bottom: 10px; + } + + .ec-year-list-container { + background: #fff; + } .year-list { &-head { - margin-top: 30px; margin-bottom: -24px; padding: 20px 30px; display: flex; diff --git a/public/react/src/modules/ecs/Ecs.js b/public/react/src/modules/ecs/Ecs.js index 307754e61..dab84e8d5 100644 --- a/public/react/src/modules/ecs/Ecs.js +++ b/public/react/src/modules/ecs/Ecs.js @@ -7,6 +7,7 @@ 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 { @@ -15,6 +16,7 @@ class Ecs extends React.Component {
+
From 665c6329d19cbdfa1dc95fb381cedd38fedbcbd3 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Tue, 17 Sep 2019 10:22:15 +0800 Subject: [PATCH 04/23] ecs: graduation requirement page --- .../ec_graduation_requirements_controller.rb | 18 +- app/models/ec_graduation_requirement.rb | 4 +- .../index.json.jbuilder | 2 +- .../show.json.jbuilder | 2 +- config/routes.rb | 2 +- .../EcSetting/GraduationRequirement/index.js | 318 +++++++++++++++++- .../GraduationRequirement/index.scss | 94 ++++++ .../ecs/EcSetting/TrainingObjective/index.js | 2 +- .../react/src/modules/ecs/EcSetting/index.js | 3 + 9 files changed, 434 insertions(+), 11 deletions(-) diff --git a/app/controllers/ecs/ec_graduation_requirements_controller.rb b/app/controllers/ecs/ec_graduation_requirements_controller.rb index 95dafdb3c..0647a7914 100644 --- a/app/controllers/ecs/ec_graduation_requirements_controller.rb +++ b/app/controllers/ecs/ec_graduation_requirements_controller.rb @@ -15,19 +15,31 @@ class Ecs::EcGraduationRequirementsController < Ecs::BaseController end def create - graduation_requirement = current_year.graduation_requirements.new + graduation_requirement = current_year.ec_graduation_requirements.new @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, create_params) render 'show' end def update - graduation_requirement = current_year.graduation_requirements.find(params[:id]) - @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(graduation_requirement, update_params) + @graduation_requirement = Ecs::SaveGraduationRequirementeService.call(current_graduation_requirement, update_params) render 'show' end + def destroy + ActiveRecord::Base.transaction do + current_graduation_requirement.destroy! + current_year.ec_graduation_requirements.where('position > ?', current_graduation_requirement.position) + .update_all('position = position - 1') + end + render_ok + end + private + def current_graduation_requirement + @_current_graduation_requirement ||= current_year.ec_graduation_requirements.find(params[:id]) + end + def create_params params.permit(:position, :content, graduation_subitems: [:content]) end diff --git a/app/models/ec_graduation_requirement.rb b/app/models/ec_graduation_requirement.rb index d0f4195d0..f9c65e28e 100644 --- a/app/models/ec_graduation_requirement.rb +++ b/app/models/ec_graduation_requirement.rb @@ -1,4 +1,6 @@ class EcGraduationRequirement < ApplicationRecord + default_scope { order(position: :asc) } + belongs_to :ec_year has_many :ec_graduation_subitems, dependent: :destroy @@ -7,5 +9,5 @@ class EcGraduationRequirement < ApplicationRecord validates :position, presence: true, numericality: { only_integer: true, greater_than: 0 } validates :content, presence: true - default_scope { order(position: :asc) } + accepts_nested_attributes_for :ec_graduation_subitems, allow_destroy: true end diff --git a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder index 6fbbf249b..ffb83ed23 100644 --- a/app/views/ecs/ec_graduation_requirements/index.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/index.json.jbuilder @@ -1,3 +1,3 @@ json.count @graduation_requirements.size -json.graduation_requirements @graduation_requirements, partial: 'shared/ec_graduation_requirement', as: :ec_graduation_requirement +json.graduation_requirements @graduation_requirements, partial: '/ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement diff --git a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder index 562c255a9..d3a8db1fc 100644 --- a/app/views/ecs/ec_graduation_requirements/show.json.jbuilder +++ b/app/views/ecs/ec_graduation_requirements/show.json.jbuilder @@ -1,2 +1,2 @@ -json.partial! 'shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement +json.partial! 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', ec_graduation_requirement: @graduation_requirement diff --git a/config/routes.rb b/config/routes.rb index 8098d03c9..f5c1a54d3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -715,7 +715,7 @@ Rails.application.routes.draw do resources :ec_years, only: [] do resource :ec_training_objectives, only: [:show, :create] - resources :ec_graduation_requirements, only: [:index, :create] + resources :ec_graduation_requirements, only: [:index, :create, :update, :destroy] resource :requirement_support_objectives, only: [:show, :create, :destroy] resource :subitem_support_standards, only: [:show, :create, :destroy] resource :students, only: [:show, :destroy] do diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js index ea46b2604..4ee387a73 100644 --- a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js +++ b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.js @@ -1,18 +1,27 @@ 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 { 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: [] } } @@ -24,19 +33,193 @@ class GraduationRequirement extends React.Component { 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.ec_graduation_requirements, + 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 } = this.state; + let { loading, editIndex, addState, submitState, validateState, currentEditReq, graduationRequirements, newRequirement } = this.state; return (
@@ -56,6 +239,135 @@ class GraduationRequirement extends React.Component {
+
+
+
指标点
+
内容
+
+ { + can_manager && !addState && ( + + + + ) + } +
+
+
+ { + graduationRequirements && graduationRequirements.map((item, index) => { + return can_manager && index === editIndex ? ( +
+
+
{ index + 1 }
+
+ + + +
+
+ +
+
+ { + currentEditReq.ec_graduation_subitems.map((subitem, i) => { + return ( +
+
{ index + 1 }-{ i + 1 }
+
+ + this.onEditItemContentChange(e, i)} /> + +
+
+ this.removeEditItem(i)}/> +
+
+ ) + }) + } + +
+ + +
+
+ ) : ( +
+
+
{ index + 1 }
+
{ item.content }
+ { + can_manager && ( +
+ this.showDeleteConfirm(item.id)} /> + this.showEditContent(index)}/> + { + index === graduationRequirements.length - 1 && !addState && ( + + ) + } +
+ ) + } + +
+ { + item.ec_graduation_subitems.map((subitem, i) => { + return ( +
+
{ index + 1 }-{ i + 1 }
+
{ subitem.content }
+
+ ) + }) + } +
+ ) + }) + } + + { + can_manager && addState && ( +
+
+
{ graduationRequirements.length + 1 }
+
+ + + +
+
+ +
+
+ { + newRequirement.graduation_subitems.map((subitem, i) => { + return ( +
+
{ graduationRequirements.length + 1 }-{ i + 1 }
+
+ + this.onNewReqItemContentChange(e, i)} /> + +
+
+ this.removeNewReqItem(i)}/> +
+
+ ) + }) + } + +
+ + +
+
+ ) + } +
+
diff --git a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss index e69de29bb..9d740a970 100644 --- a/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss +++ b/public/react/src/modules/ecs/EcSetting/GraduationRequirement/index.scss @@ -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; + } +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js index 859b987ee..e48cf2c84 100644 --- a/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js +++ b/public/react/src/modules/ecs/EcSetting/TrainingObjective/index.js @@ -198,7 +198,7 @@ class TrainingObjective extends React.Component {
目标分解详情
{ - itemsEditState || ( + !can_manager || itemsEditState || ( diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js index 238d8474c..4f27acb2a 100644 --- a/public/react/src/modules/ecs/EcSetting/index.js +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -10,6 +10,7 @@ import CustomLoadable from "../../../CustomLoadable"; const { Step } = Steps; const TrainingObjective = CustomLoadable(() => import('./TrainingObjective/index')) +const GraduationRequirement = CustomLoadable(() => import('./GraduationRequirement/index')) 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"]; @@ -98,6 +99,8 @@ class EcSetting extends React.Component { () }> + () }> ) } From 06ffbb390af69779079f981d68bdea0db85a272a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Tue, 17 Sep 2019 10:50:05 +0800 Subject: [PATCH 05/23] =?UTF-8?q?=E6=8C=AA=E5=B7=A5=E7=A8=8B=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/AppConfig.js | 9 +- public/react/src/modules/ecs/css/ec.css | 27 + .../modules/ecs/css/ecCourseEvaluations.css | 565 +++++++++ .../src/modules/ecs/css/ecCourseSupports.css | 352 ++++++ public/react/src/modules/ecs/css/search.svg | 1 + .../react/src/modules/ecs/ecTitle/ecTitle.css | 104 ++ .../react/src/modules/ecs/ecTitle/ecTitle.js | 100 ++ .../react/src/modules/ecs/ecTitle/img/1.png | Bin 0 -> 1618 bytes .../react/src/modules/ecs/ecTitle/img/2.png | Bin 0 -> 2093 bytes .../react/src/modules/ecs/ecTitle/img/3.png | Bin 0 -> 2030 bytes .../react/src/modules/ecs/ecTitle/img/4.png | Bin 0 -> 1589 bytes .../ecs/subroute/EcCompletionCalculation.js | 814 +++++++++++++ .../ecs/subroute/EcCourseEvaluationsbottom.js | 1037 +++++++++++++++++ .../modules/ecs/subroute/ecCourseSupports.js | 656 +++++++++++ 14 files changed, 3661 insertions(+), 4 deletions(-) create mode 100644 public/react/src/modules/ecs/css/ec.css create mode 100644 public/react/src/modules/ecs/css/ecCourseEvaluations.css create mode 100644 public/react/src/modules/ecs/css/ecCourseSupports.css create mode 100644 public/react/src/modules/ecs/css/search.svg create mode 100644 public/react/src/modules/ecs/ecTitle/ecTitle.css create mode 100644 public/react/src/modules/ecs/ecTitle/ecTitle.js create mode 100644 public/react/src/modules/ecs/ecTitle/img/1.png create mode 100644 public/react/src/modules/ecs/ecTitle/img/2.png create mode 100644 public/react/src/modules/ecs/ecTitle/img/3.png create mode 100644 public/react/src/modules/ecs/ecTitle/img/4.png create mode 100644 public/react/src/modules/ecs/subroute/EcCompletionCalculation.js create mode 100644 public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js create mode 100644 public/react/src/modules/ecs/subroute/ecCourseSupports.js diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 5d2373e84..b6f3bc0df 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -38,14 +38,15 @@ export function initAxiosInterceptors(props) { // https://github.com/axios/axios/issues/1497 // TODO 读取到package.json中的配置? - var proxy = "http://localhost:3000" + var proxy = "http://localhost:3000"; // proxy = "http://testbdweb.trustie.net" // proxy = "http://testbdweb.educoder.net" // proxy = "https://testeduplus2.educoder.net" - proxy="http://47.96.87.25:48080" + proxy="http://47.96.87.25:48080"; // wy - proxy="https://pre-newweb.educoder.net" - proxy="https://test-newweb.educoder.net" + proxy="https://pre-newweb.educoder.net"; + proxy="https://test-newweb.educoder.net"; + proxy="http://192.168.2.63:3001/"; // wy // proxy="http://192.168.2.63:3001" diff --git a/public/react/src/modules/ecs/css/ec.css b/public/react/src/modules/ecs/css/ec.css new file mode 100644 index 000000000..3c62678c9 --- /dev/null +++ b/public/react/src/modules/ecs/css/ec.css @@ -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); +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/ecCourseEvaluations.css b/public/react/src/modules/ecs/css/ecCourseEvaluations.css new file mode 100644 index 000000000..5931e9f80 --- /dev/null +++ b/public/react/src/modules/ecs/css/ecCourseEvaluations.css @@ -0,0 +1,565 @@ +.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; +} +#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; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/ecCourseSupports.css b/public/react/src/modules/ecs/css/ecCourseSupports.css new file mode 100644 index 000000000..3f1dc000a --- /dev/null +++ b/public/react/src/modules/ecs/css/ecCourseSupports.css @@ -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; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/css/search.svg b/public/react/src/modules/ecs/css/search.svg new file mode 100644 index 000000000..cf0e16c0c --- /dev/null +++ b/public/react/src/modules/ecs/css/search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/ecTitle.css b/public/react/src/modules/ecs/ecTitle/ecTitle.css new file mode 100644 index 000000000..3f6796cdd --- /dev/null +++ b/public/react/src/modules/ecs/ecTitle/ecTitle.css @@ -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; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/ecTitle.js b/public/react/src/modules/ecs/ecTitle/ecTitle.js new file mode 100644 index 000000000..f24409018 --- /dev/null +++ b/public/react/src/modules/ecs/ecTitle/ecTitle.js @@ -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 ( +
+ + + +
+ )} +} + +export default EcTitleCourseEvaluations; \ No newline at end of file diff --git a/public/react/src/modules/ecs/ecTitle/img/1.png b/public/react/src/modules/ecs/ecTitle/img/1.png new file mode 100644 index 0000000000000000000000000000000000000000..28325a3ea0f244778eee47dd36eed675131b6765 GIT binary patch literal 1618 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 literal 0 HcmV?d00001 diff --git a/public/react/src/modules/ecs/ecTitle/img/3.png b/public/react/src/modules/ecs/ecTitle/img/3.png new file mode 100644 index 0000000000000000000000000000000000000000..da3d477792d2abdfd6162658c07235d4d7ea72a1 GIT binary patch literal 2030 zcmaJ?eN}4MibEuuv#KbdnMu%8?e1lF0HSGzO_a9kI|fx*KBs5#4+4ec$)F&+qsAo{w|x z&cuY*XZZy95D0`>aj{|gE;TdzYC( zrMO+NOd)krRFX825)C0Bg+u4kv`jXS63VADIeZ>#)k+ErU~(A%pTS&31DFDUF94X7 zXBQQZhUn4-GVz*cvG9|Snt@@kfWa`E&2%%H4k3C5lh5Zf02YJAqTwDiG{=N#EHo1u zG{qnWQ7vMCF#}|xxEM8QP&Ou{;z}n|Fv8DiP3W^S;RRz@G%$ln2V5ylIZCDf?`kwY z_eL=p_>bQIBt{iEFvyUBD3pz8@y4YGxkAB$Xav+?5Tbyftf?v{WVA4TmbeS6?l?viaD5f!K!8oyyinGuS2AzPvhRYI#M)R04A~BO0!{_k;eiSp5 z&0_J`Ec~9riXm;b5j0^_SlvHZ{ zUQ6h-SOzYJ;cD)`nmuL0C&;yZKDzkf`S61#eBu#&w14+H+Cm_BrpAdy3d;}oZ(J#s zY63fd(=X{Mc{i=St*fhhPgY5N+OdwbtK**o+M({P{e9!iRVAWJA#1&sy`_Dvq+ZK@ zg)5sElV3@`(s{na`pzhS@K5HUoR+&Ax~?~m|Ne`;Y%s5U5X<_4`!M8qqriiii3m4u zS+B2cADc&fv6~?WAm_n~IvS7# zja6yR{xobRq2Yb(+~SHwwgvpcWrbt&MZV}TLVB>VRynpn^iHzwqzq^o6vV0g8;@=Z z()m`Eef{tVPUrMV@w z$>xkWPPJZ5`;&J*CQ()Us9W9T@pxCoaa)tEFekE?6uxb}&3k!(WOv)5V|8BN)b|AF z0dQ6Cj-A^l@_Sd#l^B~BR^fK;t$}X!F7C-Km1n#h+*?~l)EkROXW-&*d=jxh?^`tl z7scfk6K1_+ZZ7=fj?U!R;Q32m&JMN}DY`(7{V^}}Y~dpwd2d;J8RsXzs?QG1dE=D; zWkMzZ1@B>qKltm?eKSdJb}k*F6*N_on;vZ@wv46R9*^qC5Ta+otmSh%U#2F+zy6@C zb)GPCA`0@a&<`HE(R#I`Cm7f8bVTigJ8U#Q)*h-`VLfPS!MmhDNpg#1XUMR3@?Aft z#ZC4ySRQ6=+wk2>$Da=RUT@8dQu$ZT4Qo1Acr9Mlf7Tlz$~(7>IphoTU}8hq{&1dm z#_fs~)&SL~J?j=e$veJxg;h$5*#2ST;)nqsC*f()b|;;F@6|o(rt1pN5_mZ$weg-; z)qt_a`T%SDYBcEmqpgkS%LC9O36`8upY(N~)~R0b&-J*dg6rTX{*XELi#to>?YDdDGl0`3+SlGl*poDz|Kz^=>xr@SeF?P(#;>fAy=xY6d|e2~*WHQx zXLEg>H#_XXw|#{9D+45_){j(H0}D?+ZY?cvhpqZDY`B`VuQdK_QR+OV&}vU<6Kz%A z+)UgTOyvcx4PG4CG)Z=FAZaZAubD1lUg_G1{493@6|4QiE(|GwQd?2`MMeK_+6H&B tH}20ocR}K=M)Kl=@FW?We{Hr0kwCM3T+_#5d~HKzao literal 0 HcmV?d00001 diff --git a/public/react/src/modules/ecs/ecTitle/img/4.png b/public/react/src/modules/ecs/ecTitle/img/4.png new file mode 100644 index 0000000000000000000000000000000000000000..37dab8ea025029e44ae583f107ceed8fab863b65 GIT binary patch literal 1589 zcmaKseM}Q~7{`kYUvOkb-BjGRt8GzX zqWFS~kZiaOP{2gphOR*ZnbKmdh zd4A9DNe^zx+ZY!cA1jl|;&OA0`Ctu!U&-9r;Ephfdax`LOjeu-SP!l9p#VUU0tWdgH_f9yy*$E2!Lt;G zTAOpjZkXoTh!;!TakXENa)Vd5+`m2yiiD+P@4o1?`lnAQSp-Kdr zyyPGoN0g!Y#_Y*l;7u=g2m*`3u-EHVc-JZz&JH6woeoy2V3jHjDAIU8EnvPhnopb} z7)c)IoUGtvXh3&@;K~xER4i)XNK9b3LWXfqb#aS>5g6XVu#mwZbxjMcE^^WY z9g>xfq-zjUrV&9*y38!C$$+Sp*-BjoVlo(} zyhaB1P$Vr(d5LFU?TlV&94HoKHjU;Y8Mc;ATDhM)1g zRR1CoW3dENjvxJGfw!%+e(M}Xvt7<@sMa;y}EX9?*nCL%~;`$7<=>_ zdR4e=;QH{VOZMOITiO(T09Dy<#J47Q7x7gy)Pnjc!83yW9AH(%T3s^01Ty?*p#btWL*Y6MkO?Ad{B zl@Q%)0OFRlGH2P`K8szeJw5-Ij)r91zb$qz-X7Q_cB%k#{LS5!#mh%Qpl1g`0o!*= zzFJ{@MGCB`a(X0A7YaC+%HL((m%m^$3*3SIEsfPj#PNfpX{md6x^G|jsi0tRVW?%~ z)XCPQ?);VyAGsQUPZ4#jBnj-RvOKoY)}DG#8=MywYwIM!p{LTbt`mccLK{iGTG!yh((?iE@uCzuDc(E{ zHV{G6!PXQ_pnPzF#HgKk#CFd9Ssd4Qby~og0hz%aQ2@f?roO)>Wm2l%NGgye?%&8g cPi8$YldXO0Giq~=O8O(uHRTyU&)Qb~H>pZ(>;M1& literal 0 HcmV?d00001 diff --git a/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js new file mode 100644 index 000000000..51e127ebd --- /dev/null +++ b/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js @@ -0,0 +1,814 @@ +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; i10){ + 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{ + 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(目标{length-i}) + // target_listres.push(目标{i+1}) + target_listres.push(目标{length-i}) + } + return target_listres + } + + let TargetresLists = (length) => { + let target_listress = []; + for(let i = 0; i < length; i++) { + // target_listres.push(目标{length-i}) + target_listress.push(目标{i+1}) + // target_listres.push(目标{length-i}) + } + 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() + }else{ + target_listres.push() + } + + } + 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( + {/*
{value[i].total_score}
*/} +
100%
+
) + }else{ + target_listres.push( + {/*
{value[i].score}
*/} + {/*
占比{(value[i].rate*100).toFixed(2)}%
*/} +
+ {(value[i].rate*100).toFixed(2)}% +
+
) + } + + } + return target_listres + }else{ + target_listres.push( + {/*
{value[i].total_score}
*/} +
--
+
) + 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( + //
{value[i].score.toFixed(2)}
+ //
) + // }else{ + // target_listres.push( + //
{value[i].score.toFixed(2)}
+ //
) + // } + + if(i +
{value[i].score.toFixed(2)}
+ ) + } + + } + return target_listres + } + } + return ( +
+ +
+
{completionlist}
+
+ { + calculatesetype===true? +
+ 知道啦 +
+ : +
+ 取消 + 确定 +
+ } + + + +
+ +
+ + + +
+ +
+ 课程体系 > + {schooldata.ec_course_name} 达成评价详情 + {/* 导出培养目标 */} +
系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
+ +
+ +
+ 1.课程目标 + 2.课程考核方式与数据来源 + 3.成绩等级设置 + 4.课程目标评价方法 + 5.课程达成评价结果 + {/* 课程体系: + { + evaluate_result===false?未达成:达成 + } + */} + 计算 + + 导出评价详情 + +
+ +
+ +
+ +

+ 课程目标 + 达成结果 + 达成标准(分) + 实际达成 + 权重 +

+ + { Spintype===true?}/>:"" } + + + { target_list.length===0&&Spintype===false? +
  • + -- + -- + -- + -- + -- + -- +
  • :""} + + + {Spintype===false?target_list.map((item,key)=>{ + + return( +
  • + {key+1} + {item.content} + {item.result} + {item.standard_grade} + {item.real_grade} + {item.weigths} +
  • + ) + + }):"" + } + + +
    + +
    + +
    + 毕业要求指标点达成评价结果 + 注: 代表支持指标点;代表不支持指标点 +
    + +
    + +
    + + { + graduation_list.length===0? +

    + 毕业要求 + {5} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(5)} +

    + :"" + } + + { Spintype===true?}/>:"" } + + { + graduation_list.length===0&&Spintype===false? +
  • + {/* {item.ec_graduation_name} */} + {1} + {"--"} + {"--"} + {"--"} + {"--"} + 立即配置 + {TargetresContentList(5,[2,2,2,2,2])} +
  • + :"" + } + { + Spintype===false?graduation_list.map((item,key)=>{ + + if(key===0){ + return( +

    5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> + 毕业要求 + {item.ec_subitem_content} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(ec_course_targets_count)} +

    + ) + } + + }):"" + } + + + { + Spintype===false?graduation_list.map((item,key)=>{ + + return( +
  • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> + {/* {item.ec_graduation_name} */} + {key+1} + {item.ec_subitem_content} + {item.result} + {item.reach_target===null?0:item.reach_target} + {item.reach_real_target===null?0:item.reach_real_target} + {item.weight===null||item.weight===0?立即配置:{item.weight}} + {TargetresContentList(ec_course_targets_count,item.target_position)} +
  • + ) + + }):"" + } +
    + +
    + +
    + 课程总评成绩表 +
    + +
    + +
    + +

    5 ? (180 * total_rate_data+226+16) : 1200+"px"}}> + {/*序号*/} + 课程目标 + {/*姓名*/} + {/*学号*/} + {TargetresLists(total_rate_data-1)} + 总评成绩 +

    + {/*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( + //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // 占比 + // {/*colorTransparent*/} + // {/* 平均数 */} + // {/* 平均数 */} + // {/* {Total_rate_dataList(total_rate_data-1,i.total_rate)} + //
  • + // ) + + // } + + // }) */} + } + { Spintype===true?}/>:"" } + { + Spintype===false?
  • 5 ? (180 * total_rate_data+226+16) : 1200 + "px"}}> + 占比 + {/*colorTransparent*/} + {/* 平均数 */} + {/* 平均数 */} + {Total_rate_dataList(course_total_score)} + { + course_total_score.length===0? --:"" + } +
  • :"" + } + {/*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( + //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // {/*{k+1}*/} + // 平均分 + // {/*{i.student_scores.name}*/} + // {/*{i.student_scores.student_number}*/} + // {newTotal_rate_dataList(total_rate_data-1,i.student_scores.target_info)} + // {i.student_scores.total_score.toFixed(2)} + //
  • + // ) + + // } + + // }) + } + { + Spintype===false?
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + {/*{k+1}*/} + 平均分 + {/*{i.student_scores.name}*/} + {/*{i.student_scores.student_number}*/} + {newTotal_rate_dataList(course_total_score-1,course_total_score)} + {/* {course_total_score.length===0?"":course_total_score[course_total_score-1].total_score} */} + { + course_total_score.length===0? --:{course_total_scoreaverage} + } +
  • :"" + } + + +
  • 1136?113*(total_rate_data+4):1136+"px",display:morelisttype===true?"block":"none"}}> + this.showmorelist()}>加载更多 +
  • +
    + + + +
    + +
    + 课程目标成绩分析 +
    + +
    + + +
    + +

    + 课程目标 + 平均分 + 最高分数 + 最低分数 + 90分以上 + 80-89分 + 70-79分 + 60-69分 + 50-59分 + 低于50分 +

    + + { + Spintype===false?target_score.map((i,k)=>{ + + return( +
  • + {k+1} + {i.average_score} + {i.top_score} + {i.low_score} + +
    {i.from90[0]}人
    +
    {(i.from90[1]).toFixed(2)}%
    +
    + +
    {i.from80[0]}人
    +
    {(i.from80[1]).toFixed(2)}%
    +
    + +
    {i.from70[0]}人
    +
    {(i.from70[1]).toFixed(2)}%
    +
    + +
    {i.from60[0]}人
    +
    {(i.from60[1]).toFixed(2)}%
    +
    + +
    {i.from50[0]}人
    +
    {(i.from50[1]).toFixed(2)}%
    +
    + +
    {i.from_down[0]}人
    +
    {(i.from_down[1]).toFixed(2)}%
    +
    +
  • + ) + + }):"" + } + + { Spintype===true?}/>:"" } + + {target_score.length===0&&Spintype===false? +
  • + -- + -- + -- + -- + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    +
  • :""} + +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( EcCompletionCalculation ) ); + diff --git a/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js new file mode 100644 index 000000000..bf1bda068 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js @@ -0,0 +1,1037 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import classNames from 'classnames' + +import axios from 'axios'; + +import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Select,InputNumber,message,Modal,Input,Radio,Spin,Icon,Tooltip } from 'antd'; + +import 'antd/dist/antd.css'; + +import '../css/ecCourseEvaluations.css'; +import EcTitleCourseEvaluations from "../ecTitle/ecTitle"; + +const $ = window.$; +class EcCourseEvaluationsbottom extends Component { + constructor(props) { + super(props) + this.state={ + totalevaluations_list:[], + ec_course_target_id:0, + achievement_list:[], + evaluations_listSelec:[], + evaluations_lists: [], + evaluation_subitems_lists: [], + evaluations_list:[], + evaluation_subitems_list:{}, + achievement_methods:[], + ec_course_target_name:"", + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + spinningstate:true, + schooldata:{}, + sequenceid:0, + target_id:null, + titlemessages:"提示", + Modallists:"", + eacoursetype:false, + eacoursesavetypes:false, + newec_course_idbottom:undefined, + methodologytype:false, + meweacoursetype:false, + newshowredvalue:false, + percentagetype:false, + ismanager:false + } + } + getec_course_achievement_methods=()=>{ + const {newec_course_idbottom}=this.state; + if(newec_course_idbottom!=undefined){ + const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + } + // this.setState({ + // achievement_list:[ + // {target_evaluate_data: [ + // { + // evaluate_id: 24, + // evaluate_name: "期末考试", + // evaluation_relates_data: [ + // {evaluation_relates_id: 31, evaluation_relates_name: "期末考试1目标1考题"}, + // {evaluation_relates_id: 32, evaluation_relates_name: "期末考试1目标2考题"} + // ], + // percentage: 100, + // score: 15 + // } + // ], + // target_id: 5 + // }, + // ], + // spinningstate:false + // }) + + + } + + getNavigationData=(ec_course_id)=>{ + // const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id; + const jol =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id; + axios.get(jol, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + + }) + .catch(function (error) { + console.log(error); + }); + } + componentDidMount(){ + let ec_course_id=this.props.match.params.ec_course_id; + const url = `/ec_course_achievement_methods?ec_course_id=`+ec_course_id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + + this.getNavigationData(ec_course_id); + this.setState({ + newec_course_idbottom:ec_course_id + }) + } + editecCourseEvaluationslist=(e)=>{ + let id =e.target.getAttribute("target_id"); + let newid =e.target.name; + + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + target_id:id, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").show(); + // $("#SystemParametersbottom").show(); + // let offsettop=$("#ecCourseEvaluationsbottomsubmit").position().top||$("#ecCourseEvaluationsbottomsubmit").scrollTop || $("#ecCourseEvaluationsbottomsubmit").pageYOffset; + // window.scrollTo(0, offsettop) + + let {evaluations_list,evaluation_subitems_list,achievement_methods} = this.state; + this.setState({ + achievement_methods:undefined, + selectevaluation_phase:[], + course_select_value:'', + evaluations_lists:[], + sequenceid:newid, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false + }) + + let newevaluations_list=[]; + let newevaluation_subitems_list=new Object (); + let newachievement_methods=[]; + const url = `/ec_course_achievement_methods/edit_course_target?ec_course_target_id=`+id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + if(response.status===200){ + if(response.data.evaluation_phase_list.length===0){ + this.setState({ + achievement_methods:undefined + }) + let newObject=new Object (); + newachievement_methods.push(newObject) + } + + if(response.data.evaluation_phase_list.length>0){ + let evaluation_phase_list=response.data.evaluation_phase_list; + let evaluations_list=response.data.evaluations_list; + for(var i=0; i{ + + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=keythis.key; + let list=totalevaluations_list.evaluations_list; + // 点击切换清空 + for(var z=0; z0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + let{totalevaluations_list,achievement_methods}=this.state; + let newachievement_methods=[]; + let id; + if(value.length>0){ + + newachievement_methods=achievement_methods + for(var j=0; j{ + let id=parseInt(keynum.key); + let{achievement_methods}=this.state; + let newachievement_methods=achievement_methods; + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + var value=parseFloat(e.target.value); + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + let value=parseFloat(e.target.value); + + if(value>100){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比请输入0~100的数', + meweacoursetype:true, + newshowredvalue:true + }) + value=100 + } + + if(value<0){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能小于0', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + if(value===""||value===null||value===undefined){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能为空', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + newachievement_methods.push(newlist); + this.setState({ + achievement_methods:newachievement_methods + }); + } + Delethandevaluation=(e)=>{ + let {achievement_methods} = this.state; + let id =e.target.getAttribute("index"); + let newachievement_methods=achievement_methods; + newachievement_methods.splice(id,1); + this.setState({ + achievement_methods:newachievement_methods + }); + } + + + EvaluationsSaveonloadgetdata=(id)=>{ + const url = `/ec_course_achievement_methods?ec_course_id=`+id + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + + }).catch(function (error) { + console.log(error); + this.setState({ + spinningstate:false + }) + }); + + + } + ecrestoration=()=>{ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + } + + SaveCourseEvaluationsbottom=()=>{ + let ec_course_id=this.props.match.params.ec_course_id; + this.setState({ + buttomSaveCourseEvaluationsbottom:'', + percentagetype:true + }) + let {newec_course_target_id,achievement_methods} = this.state; + + + for(var j=0; j100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比不能超过总和100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + if(percentagenum<100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比总和要等于100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + for(var i=0;i { + if(response.data.status===0){ + this.setState({ + target_id:null, + newec_course_idbottom:response.data.ec_course_id, + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + // Modallists:response.data.message, + // eacoursetype:true, + Modallists:' ', + meweacoursetype:false, + achievement_methods:undefined, + eacoursesavetypes:false, + newshowredvalue:false, + ismanager:response.data.is_manager + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.EvaluationsSaveonloadgetdata(response.data.ec_course_id); + this.getNavigationData(ec_course_id); + + }else if(response.data.status===-1){ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + Modallists:response.data.message, + eacoursetype:true, + }) + } + }).catch((error) => { + console.log(error) + }) + } + CancelecCourseEvaluationsbottom=()=>{ + this.setState({ + achievement_methods:undefined, + target_id:null, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.getec_course_achievement_methods(); + } + + selectsonFocuslist=(e,key)=>{ + let value =e.course_select_value; + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=key; + let list=totalevaluations_list.evaluations_list; + this.setState({ + evaluations_lists: evaluation_subitems_list[value], + evaluation_subitems_lists: evaluation_subitems_list[value][0] + }); + + if(newachievement_methods.length===0){ + for(var i=0; i0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + this.setState({ + eacoursetype:false + }) + } + render() { + const Option = Select.Option; + let {schooldata,achievement_list,spinningstate,evaluations_list,evaluations_lists,newec_course_target_id,achievement_methods,ec_course_target_name,buttomSaveCourseEvaluationsbottom,sequenceid,target_id, + titlemessages, + Modallists, + eacoursetype, + eacoursesavetypes, + methodologytype, + newec_course_idbottom, + meweacoursetype, + percentagetype, + ismanager + } = this.state; + return ( +
    +
    + +
    +
    {Modallists}
    +
    +
    + 取消 + 确定 +
    +
    + + {/*导航*/} + {/*
    */} + + {/*

    */} + {/*课程列表 > */} + {/* {schooldata.ec_course_name} 课程考核方式与数据来源*/} + {/*/!* *!/*/} + {/*/!* 导出培养目标 *!/*/} + {/*导出策略*/} + {/*

    */} + + {/*
    */} + {/*课程考核标准*/} + {/*(请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统)*/} + {/*在线课堂:{course_name}*/} + {/*导入课堂数据*/} + {/*
    */} + + {/*
    */} + + +
    + +

    + 课程体系 > + {schooldata.ec_course_name} +

    请结合本课程的教学情况,修改说明每个课程目标的评价环节和评估方式 window.elasticLayer(3533)}>查看详情
    + + {/*课程考核方式与数据来源*/} + {/* */} + {/* 导出培养目标 */} + + 导出评价方法 + +

    + +
    + {/*课程目标达成方法*/} + 1.课程目标 + 2.课程考核方式与数据来源 + 3.成绩等级设置 + 4.课程目标评价方法 + 5.课程达成评价结果 + (各环节平均得分*占比)之和/(各环节总分*占比)之和 +
    + +
    + +
    + +

    + 课程目标 + 评价环节 + 数据内容 + + 操作 + + 评价占比 + 支撑总分值 +

    + + { + achievement_list.length===0?}/>:achievement_list.map((item,key)=>{ + return( +
    + { + item.target_evaluate_data.length===0? +
  • +
    + {key+1} + + + + + + + + +
    +
    + +
    +
    +
    + + + +
    +
    + + +
    +
    + +
    +
    + + {/* 修改start*/} +
    +
    + {/*
    */} +
    +
    + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
    +
    + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + return( +
    +
    + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} id={itemkey} style={{ width: '11%' }} placeholder="请输入占比"/> + % + +
    + + + + + + +
    +
    +
    +
    +
    + ) + }) + } + {Modallists} +
    +
    保存
    +
    取消
    +
    +
    +
    + {/* 修改end*/} + + + +
  • + :item.target_evaluate_data.map((i,k)=>{ + return( +
  • +
    + {key-k===key?key+1:""} + + + {i.evaluate_name} + + + { + i.evaluation_relates_data.map((y,e)=>{ + return( +
    {y.evaluation_relates_name+" "}
    + ) + }) + } +
    + { + key-k===key? +
    +
    + +
    +
    +
    : + +
    +
    + +
    +
    +
    + } + + + +
    {i.percentage+"%"}
    +
    + + +
    {i.score}
    +
    + +
    +
    + {/* 修改start*/} +
    +
    +
    +
    + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
    +
    + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + + return( +
    +
    + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} + id={itemkey} style={{ width: '11%' }} + placeholder="请输入占比"/> + % + +
    + + + + + + +
    +
    +
    +
    +
    + ) + }) + } + {Modallists} +
    +
    保存
    +
    取消
    +
    +
    +
    + {/* 修改end*/} + +
  • + + ) + + }) + } +
    + ) + }) + } +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( EcCourseEvaluationsbottom ) ); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecCourseSupports.js b/public/react/src/modules/ecs/subroute/ecCourseSupports.js new file mode 100644 index 000000000..e5f5b6ccd --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseSupports.js @@ -0,0 +1,656 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import classNames from 'classnames' + +import axios from 'axios'; + +import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd'; + +import EcTitleCourseEvaluations from '../ecTitle/ecTitle' + +import 'antd/dist/antd.css'; + +import '../css/ecCourseSupports.css'; + +const $ = window.$; +class ecCourseSupports 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 jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; + axios.get(jol, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + }) + .catch(function (error) { + console.log(error); + }); + + + const url = `/ec_course_supports?ec_year_id=`+ec_year_id; + axios.get(url, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + this.setState({ + data:response.data + }) + } + if(response.data.course_support_data.length===0){ + this.setState({ + Supportstype:true, + Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据' + }) + } + }) + .catch(function (error) { + console.log(error); + }); + + // this.setState({ + // data:{course_count: 14, + // course_support_data: [ + // {course_data: [{ + // name: "军事课堂", + // top_relation: true, + // weigths: 0.1 + // }, { + // name: "大学生心理健康教育", + // top_relation: true, + // weigths: 0.2 + // }], + // ec_graduation_subitem_id: 2, + // num_total: 2, + // sequence_num: "1-1", + // weights_total: 0.30000000000000004, + // }, + // ], + // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", + // ec_year_id: 1, + // max_support_count: 12, + // subitems_count: 7, + // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" + // } + // }) + + } + 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, { + withCredentials: true, + }) + .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{ + 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{ + 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;j1){ + 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{ + + 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 { + + 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( +
    支撑课程 +
    (权值) +
    +
    ) + } + return res + } + + return ( +
    + +
    +
    {Supportslist}
    +
    + +
    + + +
    + + + +
    + +
    + 课程体系对毕业要求的支撑 + {/* 导出培养目标 */} + + 导出课程体系支撑矩阵 + +
    用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 window.elasticLayer(3534)} >查看详情
    + +
    +
    + 毕业要求指标点({data.subitems_count} + 课程体系({data.course_count} +
    + +
    + +
    + +

    1200? 140*data.max_support_count : 1200+"px"}}> + 毕业要求指标点 + {list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)} + 合计 +

    +
    + { + data.course_support_data===undefined? }/>:data.course_support_data.map((item,key)=>{ + + return ( +
  • 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}> + + {item.sequence_num} + + + + { + item.course_data.map((t,kes)=>{ + return( + +
    {t.name.length>12?t.name.substring(0, 10)+"...":t.name}
    +
    ({t.weigths})
    +
    + ) + + }) + } + + +
    +
    +
    {item.num_total===0?" ":item.num_total}
    +
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    +
    +
    + {data.is_manager===false?"": + + } +
    +
    + +
    + +

    + +

    + 指标点 {index} + 支撑课程 + + 权重(∑=1) + (精确到两位小数) + + 关联度最高 +

    + +
    + + { + editcourse.map((it,key)=>{ + + return( +
    + + + + +
    + +
    + + + + +
    + + + +
    + +
    + ) + }) + } + +
    + {Supportslist} +
    + 合计: {editcourse.length} + 合计: {editnum} +
    + +
    +
    保存
    +
    取消
    +
    + +

    + + +
  • + ) + }) + } +
    +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( ecCourseSupports ) ); + From 3eb054ef2bb4c96a21eedfdae42eda9e7b629ae1 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Tue, 17 Sep 2019 14:07:02 +0800 Subject: [PATCH 06/23] ecs: fix export xlsx error --- .../average_score_import_template.xlsx.axlsx | 2 +- app/views/ecs/course_targets/index.xlsx.axlsx | 2 +- .../ec_graduation_requirements/index.xlsx.axlsx | 15 +++++++++------ .../graduation_course_supports/show.xlsx.axlsx | 2 +- app/views/ecs/reach_evaluations/show.xlsx.axlsx | 2 +- .../show.xlsx.axlsx | 2 +- .../ecs/subitem_support_standards/show.xlsx.axlsx | 2 +- 7 files changed, 15 insertions(+), 12 deletions(-) diff --git a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx index 900ff5888..934e1c4be 100644 --- a/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx +++ b/app/views/ecs/course_evaluations/average_score_import_template.xlsx.axlsx @@ -13,7 +13,7 @@ wb.styles do |style| name = course_evaluation.name items_size = course_evaluation.ec_course_evaluation_subitems.count - sheet.add_row name, style: bg_style + sheet.add_row [name], style: bg_style sheet.merge_cells wb.rows.first.cells[(1..(items_size * course_evaluation.evaluation_count))] data = [] diff --git a/app/views/ecs/course_targets/index.xlsx.axlsx b/app/views/ecs/course_targets/index.xlsx.axlsx index a188ad95c..ef4215b03 100644 --- a/app/views/ecs/course_targets/index.xlsx.axlsx +++ b/app/views/ecs/course_targets/index.xlsx.axlsx @@ -15,7 +15,7 @@ wb.styles do |style| name = "#{@_current_course.name}课程目标" wb.add_worksheet(name: name) do |sheet| - sheet.add_row name, style: title_style + sheet.add_row [name], style: title_style sheet.add_row [] sheet.add_row [] diff --git a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx index aeb802329..9a2081861 100644 --- a/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx +++ b/app/views/ecs/ec_graduation_requirements/index.xlsx.axlsx @@ -6,15 +6,15 @@ wb = xlsx_package.workbook wb.styles do |style| title_style = style.add_style(sz: 16, height: 20, b: true) ec_year_style = style.add_style(sz: 10, height: 14) - label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center }) + label_style = style.add_style(sz: 11, b: true, bg_color: '90EE90', alignment: { horizontal: :center, vertical: :center }) content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求及指标点') do |sheet| - sheet.add_row '毕业要求及指标点', style: title_style + sheet.add_row ['毕业要求及指标点'], style: title_style sheet.add_row [] - sheet.add_row ['专业代码', major.code], style: ec_year_style + sheet.add_row ['专业代码', major.code.to_s + ' '], style: ec_year_style sheet.add_row ['专业名称', major.name], style: ec_year_style sheet.add_row ['学年', "#{ec_year.year}学年"], style: ec_year_style @@ -32,12 +32,15 @@ wb.styles do |style| end items_size = requirement.ec_graduation_subitems.size - sheet.merge_cells("A#{index}:A#{index + items_size}") - sheet.merge_cells("B#{index}:B#{index + items_size}") + if items_size.zero? + sheet.add_row [requirement_content, ''], style: content_style + else + sheet.merge_cells("A#{index + 1}:A#{index + items_size}") + end index += items_size end - sheet.column_widths [400, 400] + sheet.column_widths 100, 100 end end \ No newline at end of file diff --git a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx index fd1a44935..e2c2599ec 100644 --- a/app/views/ecs/graduation_course_supports/show.xlsx.axlsx +++ b/app/views/ecs/graduation_course_supports/show.xlsx.axlsx @@ -14,7 +14,7 @@ wb.styles do |style| tip_style = style.add_style(sz: 11, height: 16, color: 'FFA07A') wb.add_worksheet(:name => '课程体系对毕业要求的支撑') do |sheet| - sheet.add_row '课程体系VS毕业要求', style: title_style + sheet.add_row ['课程体系VS毕业要求'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..(3 + max_support_length - 1))] sheet.add_row [] diff --git a/app/views/ecs/reach_evaluations/show.xlsx.axlsx b/app/views/ecs/reach_evaluations/show.xlsx.axlsx index a62e4f6c2..a79d059a3 100644 --- a/app/views/ecs/reach_evaluations/show.xlsx.axlsx +++ b/app/views/ecs/reach_evaluations/show.xlsx.axlsx @@ -10,7 +10,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(name: '达成度-毕业要求综合评价报表') do |sheet| - sheet.add_row '培养目标及目标分解', style: title_style + sheet.add_row ['达成度-毕业要求综合评价报表'], style: title_style sheet.merge_cells("A1:D1") sheet.add_row [] diff --git a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx index 934ad2941..6534ce36a 100644 --- a/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx +++ b/app/views/ecs/requirement_support_objectives/show.xlsx.axlsx @@ -16,7 +16,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对培养目标的支撑') do |sheet| - sheet.add_row '毕业要求 vs 培养目标矩阵', style: title_style + sheet.add_row ['毕业要求 vs 培养目标矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..subitem_size)] diff --git a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx index e12f517f3..8329a27ee 100644 --- a/app/views/ecs/subitem_support_standards/show.xlsx.axlsx +++ b/app/views/ecs/subitem_support_standards/show.xlsx.axlsx @@ -17,7 +17,7 @@ wb.styles do |style| content_style = style.add_style(sz: 11, height: 16, border: { style: :thin, color: '000000' }) wb.add_worksheet(:name => '毕业要求对通用标准的支撑') do |sheet| - sheet.add_row '毕业要求 vs 通用标准矩阵', style: title_style + sheet.add_row ['毕业要求 vs 通用标准矩阵'], style: title_style sheet.merge_cells wb.rows.first.cells[(1..standards_size)] From d61e24d42376312add66a26944099a582a2122ef Mon Sep 17 00:00:00 2001 From: p31729568 Date: Tue, 17 Sep 2019 14:20:30 +0800 Subject: [PATCH 07/23] ecs: fix api view render error --- app/views/ecs/course_evaluations/index.json.jbuilder | 2 +- app/views/ecs/course_evaluations/show.json.jbuilder | 2 +- app/views/ecs/course_evaluations/slimmer.json.jbuilder | 2 +- app/views/ecs/course_targets/index.json.jbuilder | 2 +- app/views/ecs/ec_courses/search.json.jbuilder | 2 +- app/views/ecs/graduation_course_supports/create.json.jbuilder | 2 +- app/views/ecs/graduation_course_supports/show.json.jbuilder | 2 +- app/views/ecs/requirement_support_objectives/show.json.jbuilder | 2 +- app/views/ecs/score_levels/show.json.jbuilder | 2 +- app/views/ecs/students/show.json.jbuilder | 2 +- app/views/ecs/subitem_support_standards/show.json.jbuilder | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/views/ecs/course_evaluations/index.json.jbuilder b/app/views/ecs/course_evaluations/index.json.jbuilder index e1c63d44d..b120bccc2 100644 --- a/app/views/ecs/course_evaluations/index.json.jbuilder +++ b/app/views/ecs/course_evaluations/index.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation', as: :ec_course_evaluation diff --git a/app/views/ecs/course_evaluations/show.json.jbuilder b/app/views/ecs/course_evaluations/show.json.jbuilder index b03ddc076..f67053183 100644 --- a/app/views/ecs/course_evaluations/show.json.jbuilder +++ b/app/views/ecs/course_evaluations/show.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation +json.partial! 'ecs/course_evaluations/shared/ec_course_evaluation', ec_course_evaluation: @course_evaluation diff --git a/app/views/ecs/course_evaluations/slimmer.json.jbuilder b/app/views/ecs/course_evaluations/slimmer.json.jbuilder index 929cfe7be..6e0faef3e 100644 --- a/app/views/ecs/course_evaluations/slimmer.json.jbuilder +++ b/app/views/ecs/course_evaluations/slimmer.json.jbuilder @@ -1 +1 @@ -json.course_evaluations @course_evaluations, partial: 'shared/ec_course_evaluation_slim', as: :ec_course_evaluation +json.course_evaluations @course_evaluations, partial: 'ecs/course_evaluations/shared/ec_course_evaluation_slim', as: :ec_course_evaluation diff --git a/app/views/ecs/course_targets/index.json.jbuilder b/app/views/ecs/course_targets/index.json.jbuilder index 6590ecc10..9ec4af823 100644 --- a/app/views/ecs/course_targets/index.json.jbuilder +++ b/app/views/ecs/course_targets/index.json.jbuilder @@ -1,2 +1,2 @@ -json.course_targets @course_targets, partial: 'shared/course_target', as: :ec_course_target +json.course_targets @course_targets, partial: 'ecs/course_targets/shared/course_target', as: :ec_course_target diff --git a/app/views/ecs/ec_courses/search.json.jbuilder b/app/views/ecs/ec_courses/search.json.jbuilder index fc22586d7..cf00a2b98 100644 --- a/app/views/ecs/ec_courses/search.json.jbuilder +++ b/app/views/ecs/ec_courses/search.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.ec_courses @ec_courses, partial: 'shared/ec_course_slim', as: :ec_course \ No newline at end of file +json.ec_courses @ec_courses, partial: 'ecs/ec_courses/shared/ec_course_slim', as: :ec_course \ No newline at end of file diff --git a/app/views/ecs/graduation_course_supports/create.json.jbuilder b/app/views/ecs/graduation_course_supports/create.json.jbuilder index c05024911..d8749a5dc 100644 --- a/app/views/ecs/graduation_course_supports/create.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/create.json.jbuilder @@ -1 +1 @@ -json.partial! 'shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem +json.partial! 'ecs/graduation_course_supports/shared/ec_graduation_subitem', ec_graduation_subitem: @graduation_subitem diff --git a/app/views/ecs/graduation_course_supports/show.json.jbuilder b/app/views/ecs/graduation_course_supports/show.json.jbuilder index a9e4bdc22..495f9c6a9 100644 --- a/app/views/ecs/graduation_course_supports/show.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/show.json.jbuilder @@ -1,3 +1,3 @@ json.course_count @course_count -json.graduation_subitems @graduation_subitems, partial: 'shared/ec_graduation_subitem', as: :ec_graduation_subitem +json.graduation_subitems @graduation_subitems, partial: 'ecs/graduation_course_supports/shared/ec_graduation_subitem', as: :ec_graduation_subitem json.count @graduation_subitems.size diff --git a/app/views/ecs/requirement_support_objectives/show.json.jbuilder b/app/views/ecs/requirement_support_objectives/show.json.jbuilder index 1ba783304..642a5f10c 100644 --- a/app/views/ecs/requirement_support_objectives/show.json.jbuilder +++ b/app/views/ecs/requirement_support_objectives/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_requirements @graduation_requirements, partial: 'ecs/ec_graduation_requirements/shared/ec_graduation_requirement', as: :ec_graduation_requirement json.training_subitems @training_subitems, partial: 'ecs/ec_training_subitems/shared/ec_training_subitem', as: :ec_training_subitem -json.requirement_support_objectives @requirement_support_objectives, partial: 'shared/requirement_support_objective', as: :requirement_support_objective +json.requirement_support_objectives @requirement_support_objectives, partial: 'ecs/requirement_support_objectives/shared/requirement_support_objective', as: :requirement_support_objective diff --git a/app/views/ecs/score_levels/show.json.jbuilder b/app/views/ecs/score_levels/show.json.jbuilder index 0c8b76d86..dcdf63cdc 100644 --- a/app/views/ecs/score_levels/show.json.jbuilder +++ b/app/views/ecs/score_levels/show.json.jbuilder @@ -1 +1 @@ -json.score_levels @score_levels, partial: 'shared/ec_score_level', as: :ec_score_level +json.score_levels @score_levels, partial: 'ecs/score_levels/shared/ec_score_level', as: :ec_score_level diff --git a/app/views/ecs/students/show.json.jbuilder b/app/views/ecs/students/show.json.jbuilder index 352970055..468a1cfe3 100644 --- a/app/views/ecs/students/show.json.jbuilder +++ b/app/views/ecs/students/show.json.jbuilder @@ -1,2 +1,2 @@ json.count @count -json.students @students, partial: 'shared/ec_year_student', as: :ec_year_student \ No newline at end of file +json.students @students, partial: 'ecs/students/shared/ec_year_student', as: :ec_year_student \ No newline at end of file diff --git a/app/views/ecs/subitem_support_standards/show.json.jbuilder b/app/views/ecs/subitem_support_standards/show.json.jbuilder index 94fd6c5a0..a92fe7000 100644 --- a/app/views/ecs/subitem_support_standards/show.json.jbuilder +++ b/app/views/ecs/subitem_support_standards/show.json.jbuilder @@ -1,4 +1,4 @@ json.graduation_standards @graduation_standards, partial: 'ecs/shared/ec_graduation_standard', as: :ec_graduation_standard json.graduation_subitems @graduation_subitems, partial: 'ecs/shared/ec_graduation_subitem', as: :ec_graduation_subitem -json.subitem_support_standards @subitem_support_standards, partial: 'shared/subitem_support_standard', as: :subitem_support_standard +json.subitem_support_standards @subitem_support_standards, partial: 'ecs/subitem_support_standards/shared/subitem_support_standard', as: :subitem_support_standard From c41458686dcb5e4613cc557007aacfda828630cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Tue, 17 Sep 2019 17:17:09 +0800 Subject: [PATCH 08/23] =?UTF-8?q?=E5=B7=A5=E7=A8=8B=E8=AE=A4=E8=AF=81?= =?UTF-8?q?=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/config/webpack.config.dev.js | 2 +- public/react/package.json | 2 +- public/react/src/AppConfig.js | 2 +- .../react/src/modules/ecs/EcSetting/index.js | 8 +- .../modules/ecs/css/ecCourseEvaluations.css | 11 + .../src/modules/ecs/css/ecCourseSupports.css | 36 +- .../src/modules/ecs/curriculum/Curriculum.js | 245 ++++ .../modules/ecs/curriculum/Curriculumtwo.js | 32 + .../ecs/subroute/EcCompletionCalculation.js | 814 ------------- .../ecs/subroute/EcCourseEvaluationsbottom.js | 1037 ---------------- .../EcCompletionCalculation.js | 814 +++++++++++++ .../EcCourseEvaluationsbottom.js | 1039 +++++++++++++++++ .../modules/ecs/subroute/ecCourseSupports.js | 656 ----------- .../ecCourseSupports/EcCourseSupports.js | 656 +++++++++++ 14 files changed, 2833 insertions(+), 2521 deletions(-) create mode 100644 public/react/src/modules/ecs/curriculum/Curriculum.js create mode 100644 public/react/src/modules/ecs/curriculum/Curriculumtwo.js delete mode 100644 public/react/src/modules/ecs/subroute/EcCompletionCalculation.js delete mode 100644 public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js create mode 100644 public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js create mode 100644 public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js delete mode 100644 public/react/src/modules/ecs/subroute/ecCourseSupports.js create mode 100644 public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js diff --git a/public/react/config/webpack.config.dev.js b/public/react/config/webpack.config.dev.js index 18d1a4002..a04ec614c 100644 --- a/public/react/config/webpack.config.dev.js +++ b/public/react/config/webpack.config.dev.js @@ -32,7 +32,7 @@ module.exports = { // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.s // devtool: "cheap-module-eval-source-map", // 开启调试 - devtool: "eval", // 开启调试 + // devtool: "eval", // 开启调试 // These are the "entry points" to our application. // This means they will be the "root" imports that are included in JS bundle. // The first two entry points enable "hot" CSS and auto-refreshes for JS. diff --git a/public/react/package.json b/public/react/package.json index 8d7362c28..e91e61f03 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -5,7 +5,7 @@ "dependencies": { "@icedesign/base": "^0.2.5", "@novnc/novnc": "^1.1.0", - "antd": "^3.20.1", + "antd": "^3.23.2", "array-flatten": "^2.1.2", "autoprefixer": "7.1.6", "axios": "^0.18.0", diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index b6f3bc0df..b90a527ef 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -46,7 +46,7 @@ export function initAxiosInterceptors(props) { // wy proxy="https://pre-newweb.educoder.net"; proxy="https://test-newweb.educoder.net"; - proxy="http://192.168.2.63:3001/"; + proxy="http://192.168.2.63:3001"; // wy // proxy="http://192.168.2.63:3001" diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js index 238d8474c..9e88446c7 100644 --- a/public/react/src/modules/ecs/EcSetting/index.js +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -6,7 +6,7 @@ import axios from 'axios'; import './index.scss'; import CustomLoadable from "../../../CustomLoadable"; - +import Curriculum from "../../../modules/ecs/curriculum/Curriculum" const { Step } = Steps; const TrainingObjective = CustomLoadable(() => import('./TrainingObjective/index')) @@ -98,6 +98,12 @@ class EcSetting extends React.Component { () }> + {/*课程体系*/} + () }> + {/*课程体系VS毕业要求*/} + () }> ) } diff --git a/public/react/src/modules/ecs/css/ecCourseEvaluations.css b/public/react/src/modules/ecs/css/ecCourseEvaluations.css index 5931e9f80..f27ad7313 100644 --- a/public/react/src/modules/ecs/css/ecCourseEvaluations.css +++ b/public/react/src/modules/ecs/css/ecCourseEvaluations.css @@ -227,6 +227,17 @@ input{ 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; } diff --git a/public/react/src/modules/ecs/css/ecCourseSupports.css b/public/react/src/modules/ecs/css/ecCourseSupports.css index 3f1dc000a..10b6ebd91 100644 --- a/public/react/src/modules/ecs/css/ecCourseSupports.css +++ b/public/react/src/modules/ecs/css/ecCourseSupports.css @@ -25,6 +25,12 @@ color:rgba(5,16,26,1); 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; @@ -247,18 +253,28 @@ input{ .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); -} + 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; diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js new file mode 100644 index 000000000..e91ff9eb4 --- /dev/null +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -0,0 +1,245 @@ +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 Curriculumtwo = Loadable({ + loader: () => import('./Curriculumtwo'), + loading: Loading, +}) +const $ = window.$; +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 ( +
    +
    +
    + +
    + 课程体系 > + {schooldata&&schooldata.ec_course_name} 达成评价详情 + {/* 导出培养目标 */} +
    系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
    + { + titine === 4 ? + + 导出评价方法 + + :titine === 1 ? + + 导出课程目标 + + :titine===2? + + :"" + } +
    + +
    + this.onAclick(1)}>1.课程目标 + this.onAclick(2)}>2.课程考核方式与数据来源 + this.onAclick(3)}>3.成绩等级设置 + this.onAclick(4)} + >4.课程目标评价方法 + this.onAclick(5)} + >5.课程达成评价结果 + { + titine===5? + + + 导出评价详情 + + 计算 + + :titine===4? + (各环节平均得分*占比)之和/(各环节总分*占比)之和 + :titine===3? + (将学生的成绩转换成对应的等级) + :titine===2? + + (请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统) + 导入课堂数据 + + :"" + } +
    +
    + + {/*Curriculumtwo 测试用*/} + {/*课程目标*/} + (this.Ontitine(i)} />) }> + {/*课程考核方式与数据来源*/} + (this.Ontitine(i)}/>) }> + {/*成绩等级设置*/} + (this.Ontitine(i)}/>) }> + {/*课程目标评价方法*/} + (this.Ontitine(i)}/>) }> + {/*课程达成评价结果*/} + (this.Ontitine(i)}/>) }> + +
    +
    + ) + } + + +} +export default Curriculum; \ No newline at end of file diff --git a/public/react/src/modules/ecs/curriculum/Curriculumtwo.js b/public/react/src/modules/ecs/curriculum/Curriculumtwo.js new file mode 100644 index 000000000..221b2afb5 --- /dev/null +++ b/public/react/src/modules/ecs/curriculum/Curriculumtwo.js @@ -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 ( +
    + 测试 +
    + ) + } + + +} +export default Curriculumtwo; \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js deleted file mode 100644 index 51e127ebd..000000000 --- a/public/react/src/modules/ecs/subroute/EcCompletionCalculation.js +++ /dev/null @@ -1,814 +0,0 @@ -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; i10){ - 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{ - 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(目标{length-i}) - // target_listres.push(目标{i+1}) - target_listres.push(目标{length-i}) - } - return target_listres - } - - let TargetresLists = (length) => { - let target_listress = []; - for(let i = 0; i < length; i++) { - // target_listres.push(目标{length-i}) - target_listress.push(目标{i+1}) - // target_listres.push(目标{length-i}) - } - 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() - }else{ - target_listres.push() - } - - } - 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( - {/*
    {value[i].total_score}
    */} -
    100%
    -
    ) - }else{ - target_listres.push( - {/*
    {value[i].score}
    */} - {/*
    占比{(value[i].rate*100).toFixed(2)}%
    */} -
    - {(value[i].rate*100).toFixed(2)}% -
    -
    ) - } - - } - return target_listres - }else{ - target_listres.push( - {/*
    {value[i].total_score}
    */} -
    --
    -
    ) - 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( - //
    {value[i].score.toFixed(2)}
    - //
    ) - // }else{ - // target_listres.push( - //
    {value[i].score.toFixed(2)}
    - //
    ) - // } - - if(i -
    {value[i].score.toFixed(2)}
    - ) - } - - } - return target_listres - } - } - return ( -
    - -
    -
    {completionlist}
    -
    - { - calculatesetype===true? -
    - 知道啦 -
    - : -
    - 取消 - 确定 -
    - } - - - -
    - -
    - - - -
    - -
    - 课程体系 > - {schooldata.ec_course_name} 达成评价详情 - {/* 导出培养目标 */} -
    系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
    - -
    - -
    - 1.课程目标 - 2.课程考核方式与数据来源 - 3.成绩等级设置 - 4.课程目标评价方法 - 5.课程达成评价结果 - {/* 课程体系: - { - evaluate_result===false?未达成:达成 - } - */} - 计算 - - 导出评价详情 - -
    - -
    - -
    - -

    - 课程目标 - 达成结果 - 达成标准(分) - 实际达成 - 权重 -

    - - { Spintype===true?}/>:"" } - - - { target_list.length===0&&Spintype===false? -
  • - -- - -- - -- - -- - -- - -- -
  • :""} - - - {Spintype===false?target_list.map((item,key)=>{ - - return( -
  • - {key+1} - {item.content} - {item.result} - {item.standard_grade} - {item.real_grade} - {item.weigths} -
  • - ) - - }):"" - } - - -
    - -
    - -
    - 毕业要求指标点达成评价结果 - 注: 代表支持指标点;代表不支持指标点 -
    - -
    - -
    - - { - graduation_list.length===0? -

    - 毕业要求 - {5} - 达成结果 - 达成目标值 - 达成实际值 - 课程权重 - {TargetresList(5)} -

    - :"" - } - - { Spintype===true?}/>:"" } - - { - graduation_list.length===0&&Spintype===false? -
  • - {/* {item.ec_graduation_name} */} - {1} - {"--"} - {"--"} - {"--"} - {"--"} - 立即配置 - {TargetresContentList(5,[2,2,2,2,2])} -
  • - :"" - } - { - Spintype===false?graduation_list.map((item,key)=>{ - - if(key===0){ - return( -

    5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> - 毕业要求 - {item.ec_subitem_content} - 达成结果 - 达成目标值 - 达成实际值 - 课程权重 - {TargetresList(ec_course_targets_count)} -

    - ) - } - - }):"" - } - - - { - Spintype===false?graduation_list.map((item,key)=>{ - - return( -
  • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> - {/* {item.ec_graduation_name} */} - {key+1} - {item.ec_subitem_content} - {item.result} - {item.reach_target===null?0:item.reach_target} - {item.reach_real_target===null?0:item.reach_real_target} - {item.weight===null||item.weight===0?立即配置:{item.weight}} - {TargetresContentList(ec_course_targets_count,item.target_position)} -
  • - ) - - }):"" - } -
    - -
    - -
    - 课程总评成绩表 -
    - -
    - -
    - -

    5 ? (180 * total_rate_data+226+16) : 1200+"px"}}> - {/*序号*/} - 课程目标 - {/*姓名*/} - {/*学号*/} - {TargetresLists(total_rate_data-1)} - 总评成绩 -

    - {/*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( - //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> - // 占比 - // {/*colorTransparent*/} - // {/* 平均数 */} - // {/* 平均数 */} - // {/* {Total_rate_dataList(total_rate_data-1,i.total_rate)} - //
  • - // ) - - // } - - // }) */} - } - { Spintype===true?}/>:"" } - { - Spintype===false?
  • 5 ? (180 * total_rate_data+226+16) : 1200 + "px"}}> - 占比 - {/*colorTransparent*/} - {/* 平均数 */} - {/* 平均数 */} - {Total_rate_dataList(course_total_score)} - { - course_total_score.length===0? --:"" - } -
  • :"" - } - {/*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( - //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> - // {/*{k+1}*/} - // 平均分 - // {/*{i.student_scores.name}*/} - // {/*{i.student_scores.student_number}*/} - // {newTotal_rate_dataList(total_rate_data-1,i.student_scores.target_info)} - // {i.student_scores.total_score.toFixed(2)} - //
  • - // ) - - // } - - // }) - } - { - Spintype===false?
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> - {/*{k+1}*/} - 平均分 - {/*{i.student_scores.name}*/} - {/*{i.student_scores.student_number}*/} - {newTotal_rate_dataList(course_total_score-1,course_total_score)} - {/* {course_total_score.length===0?"":course_total_score[course_total_score-1].total_score} */} - { - course_total_score.length===0? --:{course_total_scoreaverage} - } -
  • :"" - } - - -
  • 1136?113*(total_rate_data+4):1136+"px",display:morelisttype===true?"block":"none"}}> - this.showmorelist()}>加载更多 -
  • -
    - - - -
    - -
    - 课程目标成绩分析 -
    - -
    - - -
    - -

    - 课程目标 - 平均分 - 最高分数 - 最低分数 - 90分以上 - 80-89分 - 70-79分 - 60-69分 - 50-59分 - 低于50分 -

    - - { - Spintype===false?target_score.map((i,k)=>{ - - return( -
  • - {k+1} - {i.average_score} - {i.top_score} - {i.low_score} - -
    {i.from90[0]}人
    -
    {(i.from90[1]).toFixed(2)}%
    -
    - -
    {i.from80[0]}人
    -
    {(i.from80[1]).toFixed(2)}%
    -
    - -
    {i.from70[0]}人
    -
    {(i.from70[1]).toFixed(2)}%
    -
    - -
    {i.from60[0]}人
    -
    {(i.from60[1]).toFixed(2)}%
    -
    - -
    {i.from50[0]}人
    -
    {(i.from50[1]).toFixed(2)}%
    -
    - -
    {i.from_down[0]}人
    -
    {(i.from_down[1]).toFixed(2)}%
    -
    -
  • - ) - - }):"" - } - - { Spintype===true?}/>:"" } - - {target_score.length===0&&Spintype===false? -
  • - -- - -- - -- - -- - -
    --人
    -
    --%
    -
    - -
    --人
    -
    --%
    -
    - -
    --人
    -
    --%
    -
    - -
    --人
    -
    --%
    -
    - -
    --人
    -
    --%
    -
    - -
    --人
    -
    --%
    -
    -
  • :""} - -
    - -
    -
    - ); - } -} - -export default SnackbarHOC() ( TPMIndexHOC ( EcCompletionCalculation ) ); - diff --git a/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js deleted file mode 100644 index bf1bda068..000000000 --- a/public/react/src/modules/ecs/subroute/EcCourseEvaluationsbottom.js +++ /dev/null @@ -1,1037 +0,0 @@ -import React, { Component } from 'react'; - -import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; - -import classNames from 'classnames' - -import axios from 'axios'; - -import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; - -import { SnackbarHOC } from 'educoder' - -import { Select,InputNumber,message,Modal,Input,Radio,Spin,Icon,Tooltip } from 'antd'; - -import 'antd/dist/antd.css'; - -import '../css/ecCourseEvaluations.css'; -import EcTitleCourseEvaluations from "../ecTitle/ecTitle"; - -const $ = window.$; -class EcCourseEvaluationsbottom extends Component { - constructor(props) { - super(props) - this.state={ - totalevaluations_list:[], - ec_course_target_id:0, - achievement_list:[], - evaluations_listSelec:[], - evaluations_lists: [], - evaluation_subitems_lists: [], - evaluations_list:[], - evaluation_subitems_list:{}, - achievement_methods:[], - ec_course_target_name:"", - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, - spinningstate:true, - schooldata:{}, - sequenceid:0, - target_id:null, - titlemessages:"提示", - Modallists:"", - eacoursetype:false, - eacoursesavetypes:false, - newec_course_idbottom:undefined, - methodologytype:false, - meweacoursetype:false, - newshowredvalue:false, - percentagetype:false, - ismanager:false - } - } - getec_course_achievement_methods=()=>{ - const {newec_course_idbottom}=this.state; - if(newec_course_idbottom!=undefined){ - const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; - axios.get(url, { - withCredentials: true, - }) - .then((response)=>{ - this.setState({ - achievement_list:response.data.achievement_list, - spinningstate:false, - ismanager:response.data.is_manager - }) - }).catch(function (error) { - console.log(error); - }); - } - // this.setState({ - // achievement_list:[ - // {target_evaluate_data: [ - // { - // evaluate_id: 24, - // evaluate_name: "期末考试", - // evaluation_relates_data: [ - // {evaluation_relates_id: 31, evaluation_relates_name: "期末考试1目标1考题"}, - // {evaluation_relates_id: 32, evaluation_relates_name: "期末考试1目标2考题"} - // ], - // percentage: 100, - // score: 15 - // } - // ], - // target_id: 5 - // }, - // ], - // spinningstate:false - // }) - - - } - - getNavigationData=(ec_course_id)=>{ - // const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id; - const jol =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id; - axios.get(jol, { - withCredentials: true, - }) - .then((response) => { - if(response.status===200){ - // if(response.data.allow_visit===false){ - // window.location.href="/403" - // } - this.setState({ - schooldata:response.data - }) - } - - }) - .catch(function (error) { - console.log(error); - }); - } - componentDidMount(){ - let ec_course_id=this.props.match.params.ec_course_id; - const url = `/ec_course_achievement_methods?ec_course_id=`+ec_course_id; - axios.get(url, { - withCredentials: true, - }) - .then((response)=>{ - this.setState({ - achievement_list:response.data.achievement_list, - spinningstate:false, - ismanager:response.data.is_manager - }) - }).catch(function (error) { - console.log(error); - }); - - this.getNavigationData(ec_course_id); - this.setState({ - newec_course_idbottom:ec_course_id - }) - } - editecCourseEvaluationslist=(e)=>{ - let id =e.target.getAttribute("target_id"); - let newid =e.target.name; - - this.setState({ - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, - target_id:id, - percentagetype:false - }) - // $("#ecCourseEvaluationsbottomsubmit").show(); - // $("#SystemParametersbottom").show(); - // let offsettop=$("#ecCourseEvaluationsbottomsubmit").position().top||$("#ecCourseEvaluationsbottomsubmit").scrollTop || $("#ecCourseEvaluationsbottomsubmit").pageYOffset; - // window.scrollTo(0, offsettop) - - let {evaluations_list,evaluation_subitems_list,achievement_methods} = this.state; - this.setState({ - achievement_methods:undefined, - selectevaluation_phase:[], - course_select_value:'', - evaluations_lists:[], - sequenceid:newid, - methodologytype:false, - Modallists:' ', - meweacoursetype:false, - eacoursesavetypes:false, - newshowredvalue:false - }) - - let newevaluations_list=[]; - let newevaluation_subitems_list=new Object (); - let newachievement_methods=[]; - const url = `/ec_course_achievement_methods/edit_course_target?ec_course_target_id=`+id; - axios.get(url, { - withCredentials: true, - }) - .then((response)=>{ - if(response.status===200){ - if(response.data.evaluation_phase_list.length===0){ - this.setState({ - achievement_methods:undefined - }) - let newObject=new Object (); - newachievement_methods.push(newObject) - } - - if(response.data.evaluation_phase_list.length>0){ - let evaluation_phase_list=response.data.evaluation_phase_list; - let evaluations_list=response.data.evaluations_list; - for(var i=0; i{ - - let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; - let newachievement_methods=achievement_methods; - let newlist=new Object (); - let location=keythis.key; - let list=totalevaluations_list.evaluations_list; - // 点击切换清空 - for(var z=0; z0){ - if(newachievement_methods[location]===undefined){ - newachievement_methods.push(newlist) - } - for(var i=0; i{ - let{totalevaluations_list,achievement_methods}=this.state; - let newachievement_methods=[]; - let id; - if(value.length>0){ - - newachievement_methods=achievement_methods - for(var j=0; j{ - let id=parseInt(keynum.key); - let{achievement_methods}=this.state; - let newachievement_methods=achievement_methods; - for(var i=0; i{ - let {achievement_methods} = this.state; - let newachievement_methods=achievement_methods; - let id=e.target.id; - var value=parseFloat(e.target.value); - for(var i=0; i{ - let {achievement_methods} = this.state; - let newachievement_methods=achievement_methods; - let id=e.target.id; - let value=parseFloat(e.target.value); - - if(value>100){ - // message.warning('占比请输入0~100的数'); - this.setState({ - Modallists:'占比请输入0~100的数', - meweacoursetype:true, - newshowredvalue:true - }) - value=100 - } - - if(value<0){ - // message.warning('占比请输入0~100的数'); - this.setState({ - Modallists:'占比不能小于0', - meweacoursetype:true, - newshowredvalue:true - }) - value=0 - } - - if(value===""||value===null||value===undefined){ - // message.warning('占比请输入0~100的数'); - this.setState({ - Modallists:'占比不能为空', - meweacoursetype:true, - newshowredvalue:true - }) - value=0 - } - - for(var i=0; i{ - let {achievement_methods} = this.state; - let newachievement_methods=achievement_methods; - let newlist=new Object (); - newachievement_methods.push(newlist); - this.setState({ - achievement_methods:newachievement_methods - }); - } - Delethandevaluation=(e)=>{ - let {achievement_methods} = this.state; - let id =e.target.getAttribute("index"); - let newachievement_methods=achievement_methods; - newachievement_methods.splice(id,1); - this.setState({ - achievement_methods:newachievement_methods - }); - } - - - EvaluationsSaveonloadgetdata=(id)=>{ - const url = `/ec_course_achievement_methods?ec_course_id=`+id - axios.get(url, { - withCredentials: true, - }) - .then((response)=>{ - this.setState({ - achievement_list:response.data.achievement_list, - spinningstate:false, - ismanager:response.data.is_manager - }) - - }).catch(function (error) { - console.log(error); - this.setState({ - spinningstate:false - }) - }); - - - } - ecrestoration=()=>{ - this.setState({ - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom - }) - } - - SaveCourseEvaluationsbottom=()=>{ - let ec_course_id=this.props.match.params.ec_course_id; - this.setState({ - buttomSaveCourseEvaluationsbottom:'', - percentagetype:true - }) - let {newec_course_target_id,achievement_methods} = this.state; - - - for(var j=0; j100){ - // message.error('提交失败!支撑占比不能超过总和100%'); - this.setState({ - Modallists:'提交失败,支撑占比不能超过总和100%', - meweacoursetype:true, - newshowredvalue:true, - percentagetype:true - }) - this.setState({ - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom - }) - return - } - if(percentagenum<100){ - // message.error('提交失败!支撑占比不能超过总和100%'); - this.setState({ - Modallists:'提交失败,支撑占比总和要等于100%', - meweacoursetype:true, - newshowredvalue:true, - percentagetype:true - }) - this.setState({ - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom - }) - return - } - for(var i=0;i { - if(response.data.status===0){ - this.setState({ - target_id:null, - newec_course_idbottom:response.data.ec_course_id, - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, - // Modallists:response.data.message, - // eacoursetype:true, - Modallists:' ', - meweacoursetype:false, - achievement_methods:undefined, - eacoursesavetypes:false, - newshowredvalue:false, - ismanager:response.data.is_manager - }) - // $("#ecCourseEvaluationsbottomsubmit").hide(); - // $("#SystemParametersbottom").hide(); - this.EvaluationsSaveonloadgetdata(response.data.ec_course_id); - this.getNavigationData(ec_course_id); - - }else if(response.data.status===-1){ - this.setState({ - buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, - Modallists:response.data.message, - eacoursetype:true, - }) - } - }).catch((error) => { - console.log(error) - }) - } - CancelecCourseEvaluationsbottom=()=>{ - this.setState({ - achievement_methods:undefined, - target_id:null, - methodologytype:false, - Modallists:' ', - meweacoursetype:false, - eacoursesavetypes:false, - newshowredvalue:false, - percentagetype:false - }) - // $("#ecCourseEvaluationsbottomsubmit").hide(); - // $("#SystemParametersbottom").hide(); - this.getec_course_achievement_methods(); - } - - selectsonFocuslist=(e,key)=>{ - let value =e.course_select_value; - let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; - let newachievement_methods=achievement_methods; - let newlist=new Object (); - let location=key; - let list=totalevaluations_list.evaluations_list; - this.setState({ - evaluations_lists: evaluation_subitems_list[value], - evaluation_subitems_lists: evaluation_subitems_list[value][0] - }); - - if(newachievement_methods.length===0){ - for(var i=0; i0){ - if(newachievement_methods[location]===undefined){ - newachievement_methods.push(newlist) - } - for(var i=0; i{ - this.setState({ - eacoursetype:false - }) - } - render() { - const Option = Select.Option; - let {schooldata,achievement_list,spinningstate,evaluations_list,evaluations_lists,newec_course_target_id,achievement_methods,ec_course_target_name,buttomSaveCourseEvaluationsbottom,sequenceid,target_id, - titlemessages, - Modallists, - eacoursetype, - eacoursesavetypes, - methodologytype, - newec_course_idbottom, - meweacoursetype, - percentagetype, - ismanager - } = this.state; - return ( -
    -
    - -
    -
    {Modallists}
    -
    -
    - 取消 - 确定 -
    -
    - - {/*导航*/} - {/*
    */} - - {/*

    */} - {/*课程列表 > */} - {/* {schooldata.ec_course_name} 课程考核方式与数据来源*/} - {/*/!* *!/*/} - {/*/!* 导出培养目标 *!/*/} - {/*导出策略*/} - {/*

    */} - - {/*
    */} - {/*课程考核标准*/} - {/*(请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统)*/} - {/*在线课堂:{course_name}*/} - {/*导入课堂数据*/} - {/*
    */} - - {/*
    */} - - -
    - -

    - 课程体系 > - {schooldata.ec_course_name} -

    请结合本课程的教学情况,修改说明每个课程目标的评价环节和评估方式 window.elasticLayer(3533)}>查看详情
    - - {/*课程考核方式与数据来源*/} - {/* */} - {/* 导出培养目标 */} - - 导出评价方法 - -

    - -
    - {/*课程目标达成方法*/} - 1.课程目标 - 2.课程考核方式与数据来源 - 3.成绩等级设置 - 4.课程目标评价方法 - 5.课程达成评价结果 - (各环节平均得分*占比)之和/(各环节总分*占比)之和 -
    - -
    - -
    - -

    - 课程目标 - 评价环节 - 数据内容 - - 操作 - - 评价占比 - 支撑总分值 -

    - - { - achievement_list.length===0?}/>:achievement_list.map((item,key)=>{ - return( -
    - { - item.target_evaluate_data.length===0? -
  • -
    - {key+1} - - - - - - - - -
    -
    - -
    -
    -
    - - - -
    -
    - - -
    -
    - -
    -
    - - {/* 修改start*/} -
    -
    - {/*
    */} -
    -
    - {/* 课程目标{sequenceid}:{ec_course_target_name} */} - 课程目标{key+1}:{ec_course_target_name} -
    -
    - { - achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ - return( -
    -
    - 评价环节 - - - - - - - - - - 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} - onInput={this.handevaluation_CoursePercentag.bind(this)} id={itemkey} style={{ width: '11%' }} placeholder="请输入占比"/> - % - -
    - - - - - - -
    -
    -
    -
    -
    - ) - }) - } - {Modallists} -
    -
    保存
    -
    取消
    -
    -
    -
    - {/* 修改end*/} - - - -
  • - :item.target_evaluate_data.map((i,k)=>{ - return( -
  • -
    - {key-k===key?key+1:""} - - - {i.evaluate_name} - - - { - i.evaluation_relates_data.map((y,e)=>{ - return( -
    {y.evaluation_relates_name+" "}
    - ) - }) - } -
    - { - key-k===key? -
    -
    - -
    -
    -
    : - -
    -
    - -
    -
    -
    - } - - - -
    {i.percentage+"%"}
    -
    - - -
    {i.score}
    -
    - -
    -
    - {/* 修改start*/} -
    -
    -
    -
    - {/* 课程目标{sequenceid}:{ec_course_target_name} */} - 课程目标{key+1}:{ec_course_target_name} -
    -
    - { - achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ - - return( -
    -
    - 评价环节 - - - - - - - - - - 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} - onInput={this.handevaluation_CoursePercentag.bind(this)} - id={itemkey} style={{ width: '11%' }} - placeholder="请输入占比"/> - % - -
    - - - - - - -
    -
    -
    -
    -
    - ) - }) - } - {Modallists} -
    -
    保存
    -
    取消
    -
    -
    -
    - {/* 修改end*/} - -
  • - - ) - - }) - } -
    - ) - }) - } -
    - -
    -
    - ); - } -} - -export default SnackbarHOC() ( TPMIndexHOC ( EcCourseEvaluationsbottom ) ); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js new file mode 100644 index 000000000..14e104e05 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js @@ -0,0 +1,814 @@ +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; i10){ + 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{ + 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(目标{length-i}) + // target_listres.push(目标{i+1}) + target_listres.push(目标{length-i}) + } + return target_listres + } + + let TargetresLists = (length) => { + let target_listress = []; + for(let i = 0; i < length; i++) { + // target_listres.push(目标{length-i}) + target_listress.push(目标{i+1}) + // target_listres.push(目标{length-i}) + } + 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() + }else{ + target_listres.push() + } + + } + 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( + {/*
    {value[i].total_score}
    */} +
    100%
    +
    ) + }else{ + target_listres.push( + {/*
    {value[i].score}
    */} + {/*
    占比{(value[i].rate*100).toFixed(2)}%
    */} +
    + {(value[i].rate*100).toFixed(2)}% +
    +
    ) + } + + } + return target_listres + }else{ + target_listres.push( + {/*
    {value[i].total_score}
    */} +
    --
    +
    ) + 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( + //
    {value[i].score.toFixed(2)}
    + //
    ) + // }else{ + // target_listres.push( + //
    {value[i].score.toFixed(2)}
    + //
    ) + // } + + if(i +
    {value[i].score.toFixed(2)}
    + ) + } + + } + return target_listres + } + } + return ( +
    + +
    +
    {completionlist}
    +
    + { + calculatesetype===true? +
    + 知道啦 +
    + : +
    + 取消 + 确定 +
    + } + + + +
    + +
    + + + +
    + +
    + 课程体系 > + {schooldata.ec_course_name} 达成评价详情 + {/* 导出培养目标 */} +
    系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
    + +
    + +
    + 1.课程目标 + 2.课程考核方式与数据来源 + 3.成绩等级设置 + 4.课程目标评价方法 + 5.课程达成评价结果 + {/* 课程体系: + { + evaluate_result===false?未达成:达成 + } + */} + 计算 + + 导出评价详情 + +
    + +
    + +
    + +

    + 课程目标 + 达成结果 + 达成标准(分) + 实际达成 + 权重 +

    + + { Spintype===true?}/>:"" } + + + { target_list.length===0&&Spintype===false? +
  • + -- + -- + -- + -- + -- + -- +
  • :""} + + + {Spintype===false?target_list.map((item,key)=>{ + + return( +
  • + {key+1} + {item.content} + {item.result} + {item.standard_grade} + {item.real_grade} + {item.weigths} +
  • + ) + + }):"" + } + + +
    + +
    + +
    + 毕业要求指标点达成评价结果 + 注: 代表支持指标点;代表不支持指标点 +
    + +
    + +
    + + { + graduation_list.length===0? +

    + 毕业要求 + {5} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(5)} +

    + :"" + } + + { Spintype===true?}/>:"" } + + { + graduation_list.length===0&&Spintype===false? +
  • + {/* {item.ec_graduation_name} */} + {1} + {"--"} + {"--"} + {"--"} + {"--"} + 立即配置 + {TargetresContentList(5,[2,2,2,2,2])} +
  • + :"" + } + { + Spintype===false?graduation_list.map((item,key)=>{ + + if(key===0){ + return( +

    5 ? (76*(ec_course_targets_count+4)+380+15):1200+"px"}}> + 毕业要求 + {item.ec_subitem_content} + 达成结果 + 达成目标值 + 达成实际值 + 课程权重 + {TargetresList(ec_course_targets_count)} +

    + ) + } + + }):"" + } + + + { + Spintype===false?graduation_list.map((item,key)=>{ + + return( +
  • 5 ? (76*(ec_course_targets_count+4)+380):1200+"px"}}> + {/* {item.ec_graduation_name} */} + {key+1} + {item.ec_subitem_content} + {item.result} + {item.reach_target===null?0:item.reach_target} + {item.reach_real_target===null?0:item.reach_real_target} + {item.weight===null||item.weight===0?立即配置:{item.weight}} + {TargetresContentList(ec_course_targets_count,item.target_position)} +
  • + ) + + }):"" + } +
    + +
    + +
    + 课程总评成绩表 +
    + +
    + +
    + +

    5 ? (180 * total_rate_data+226+16) : 1200+"px"}}> + {/*序号*/} + 课程目标 + {/*姓名*/} + {/*学号*/} + {TargetresLists(total_rate_data-1)} + 总评成绩 +

    + {/*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( + //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // 占比 + // {/*colorTransparent*/} + // {/* 平均数 */} + // {/* 平均数 */} + // {/* {Total_rate_dataList(total_rate_data-1,i.total_rate)} + //
  • + // ) + + // } + + // }) */} + } + { Spintype===true?}/>:"" } + { + Spintype===false?
  • 5 ? (180 * total_rate_data+226+16) : 1200 + "px"}}> + 占比 + {/*colorTransparent*/} + {/* 平均数 */} + {/* 平均数 */} + {Total_rate_dataList(course_total_score)} + { + course_total_score.length===0? --:"" + } +
  • :"" + } + {/*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( + //
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + // {/*{k+1}*/} + // 平均分 + // {/*{i.student_scores.name}*/} + // {/*{i.student_scores.student_number}*/} + // {newTotal_rate_dataList(total_rate_data-1,i.student_scores.target_info)} + // {i.student_scores.total_score.toFixed(2)} + //
  • + // ) + + // } + + // }) + } + { + Spintype===false?
  • 1200?(113*(total_rate_data+4.5))+63:1200+"px"}}> + {/*{k+1}*/} + 平均分 + {/*{i.student_scores.name}*/} + {/*{i.student_scores.student_number}*/} + {newTotal_rate_dataList(course_total_score-1,course_total_score)} + {/* {course_total_score.length===0?"":course_total_score[course_total_score-1].total_score} */} + { + course_total_score.length===0? --:{course_total_scoreaverage} + } +
  • :"" + } + + +
  • 1136?113*(total_rate_data+4):1136+"px",display:morelisttype===true?"block":"none"}}> + this.showmorelist()}>加载更多 +
  • +
    + + + +
    + +
    + 课程目标成绩分析 +
    + +
    + + +
    + +

    + 课程目标 + 平均分 + 最高分数 + 最低分数 + 90分以上 + 80-89分 + 70-79分 + 60-69分 + 50-59分 + 低于50分 +

    + + { + Spintype===false?target_score.map((i,k)=>{ + + return( +
  • + {k+1} + {i.average_score} + {i.top_score} + {i.low_score} + +
    {i.from90[0]}人
    +
    {(i.from90[1]).toFixed(2)}%
    +
    + +
    {i.from80[0]}人
    +
    {(i.from80[1]).toFixed(2)}%
    +
    + +
    {i.from70[0]}人
    +
    {(i.from70[1]).toFixed(2)}%
    +
    + +
    {i.from60[0]}人
    +
    {(i.from60[1]).toFixed(2)}%
    +
    + +
    {i.from50[0]}人
    +
    {(i.from50[1]).toFixed(2)}%
    +
    + +
    {i.from_down[0]}人
    +
    {(i.from_down[1]).toFixed(2)}%
    +
    +
  • + ) + + }):"" + } + + { Spintype===true?}/>:"" } + + {target_score.length===0&&Spintype===false? +
  • + -- + -- + -- + -- + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    + +
    --人
    +
    --%
    +
    +
  • :""} + +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( EcCompletionCalculation ) ); + diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js new file mode 100644 index 000000000..a8b3e19a7 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -0,0 +1,1039 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import classNames from 'classnames' + +import axios from 'axios'; + +import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Select,InputNumber,message,Modal,Input,Radio,Spin,Icon,Tooltip } from 'antd'; + +import 'antd/dist/antd.css'; + +import '../../css/ecCourseEvaluations.css'; +import EcTitleCourseEvaluations from "../../ecTitle/ecTitle"; + +const $ = window.$; + +// 课程目标评价方法 +class EcCourseEvaluationsbottom extends Component { + constructor(props) { + super(props) + this.state={ + totalevaluations_list:[], + ec_course_target_id:0, + achievement_list:[], + evaluations_listSelec:[], + evaluations_lists: [], + evaluation_subitems_lists: [], + evaluations_list:[], + evaluation_subitems_list:{}, + achievement_methods:[], + ec_course_target_name:"", + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + spinningstate:true, + schooldata:{}, + sequenceid:0, + target_id:null, + titlemessages:"提示", + Modallists:"", + eacoursetype:false, + eacoursesavetypes:false, + newec_course_idbottom:undefined, + methodologytype:false, + meweacoursetype:false, + newshowredvalue:false, + percentagetype:false, + ismanager:false + } + } + getec_course_achievement_methods=()=>{ + const {newec_course_idbottom}=this.state; + if(newec_course_idbottom!=undefined){ + const url = `/ec_course_achievement_methods?ec_course_id=`+newec_course_idbottom; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + } + // this.setState({ + // achievement_list:[ + // {target_evaluate_data: [ + // { + // evaluate_id: 24, + // evaluate_name: "期末考试", + // evaluation_relates_data: [ + // {evaluation_relates_id: 31, evaluation_relates_name: "期末考试1目标1考题"}, + // {evaluation_relates_id: 32, evaluation_relates_name: "期末考试1目标2考题"} + // ], + // percentage: 100, + // score: 15 + // } + // ], + // target_id: 5 + // }, + // ], + // spinningstate:false + // }) + + + } + + getNavigationData=(ec_course_id)=>{ + // const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id+"&ec_course_id="+ec_course_id; + const jol =`/ec_major_schools/get_navigation_data?ec_course_id=`+ec_course_id; + axios.get(jol, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + + }) + .catch(function (error) { + console.log(error); + }); + } + componentDidMount(){ + let ec_course_id=this.props.match.params.ec_course_id; + const url = `/ec_course_achievement_methods?ec_course_id=`+ec_course_id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + }).catch(function (error) { + console.log(error); + }); + + this.getNavigationData(ec_course_id); + this.setState({ + newec_course_idbottom:ec_course_id + }) + } + editecCourseEvaluationslist=(e)=>{ + let id =e.target.getAttribute("target_id"); + let newid =e.target.name; + + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + target_id:id, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").show(); + // $("#SystemParametersbottom").show(); + // let offsettop=$("#ecCourseEvaluationsbottomsubmit").position().top||$("#ecCourseEvaluationsbottomsubmit").scrollTop || $("#ecCourseEvaluationsbottomsubmit").pageYOffset; + // window.scrollTo(0, offsettop) + + let {evaluations_list,evaluation_subitems_list,achievement_methods} = this.state; + this.setState({ + achievement_methods:undefined, + selectevaluation_phase:[], + course_select_value:'', + evaluations_lists:[], + sequenceid:newid, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false + }) + + let newevaluations_list=[]; + let newevaluation_subitems_list=new Object (); + let newachievement_methods=[]; + const url = `/ec_course_achievement_methods/edit_course_target?ec_course_target_id=`+id; + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + if(response.status===200){ + if(response.data.evaluation_phase_list.length===0){ + this.setState({ + achievement_methods:undefined + }) + let newObject=new Object (); + newachievement_methods.push(newObject) + } + + if(response.data.evaluation_phase_list.length>0){ + let evaluation_phase_list=response.data.evaluation_phase_list; + let evaluations_list=response.data.evaluations_list; + for(var i=0; i{ + + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=keythis.key; + let list=totalevaluations_list.evaluations_list; + // 点击切换清空 + for(var z=0; z0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + let{totalevaluations_list,achievement_methods}=this.state; + let newachievement_methods=[]; + let id; + if(value.length>0){ + + newachievement_methods=achievement_methods + for(var j=0; j{ + let id=parseInt(keynum.key); + let{achievement_methods}=this.state; + let newachievement_methods=achievement_methods; + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + var value=parseFloat(e.target.value); + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let id=e.target.id; + let value=parseFloat(e.target.value); + + if(value>100){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比请输入0~100的数', + meweacoursetype:true, + newshowredvalue:true + }) + value=100 + } + + if(value<0){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能小于0', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + if(value===""||value===null||value===undefined){ + // message.warning('占比请输入0~100的数'); + this.setState({ + Modallists:'占比不能为空', + meweacoursetype:true, + newshowredvalue:true + }) + value=0 + } + + for(var i=0; i{ + let {achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + newachievement_methods.push(newlist); + this.setState({ + achievement_methods:newachievement_methods + }); + } + Delethandevaluation=(e)=>{ + let {achievement_methods} = this.state; + let id =e.target.getAttribute("index"); + let newachievement_methods=achievement_methods; + newachievement_methods.splice(id,1); + this.setState({ + achievement_methods:newachievement_methods + }); + } + + + EvaluationsSaveonloadgetdata=(id)=>{ + const url = `/ec_course_achievement_methods?ec_course_id=`+id + axios.get(url, { + withCredentials: true, + }) + .then((response)=>{ + this.setState({ + achievement_list:response.data.achievement_list, + spinningstate:false, + ismanager:response.data.is_manager + }) + + }).catch(function (error) { + console.log(error); + this.setState({ + spinningstate:false + }) + }); + + + } + ecrestoration=()=>{ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + } + + SaveCourseEvaluationsbottom=()=>{ + let ec_course_id=this.props.match.params.ec_course_id; + this.setState({ + buttomSaveCourseEvaluationsbottom:'', + percentagetype:true + }) + let {newec_course_target_id,achievement_methods} = this.state; + + + for(var j=0; j100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比不能超过总和100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + if(percentagenum<100){ + // message.error('提交失败!支撑占比不能超过总和100%'); + this.setState({ + Modallists:'提交失败,支撑占比总和要等于100%', + meweacoursetype:true, + newshowredvalue:true, + percentagetype:true + }) + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom + }) + return + } + for(var i=0;i { + if(response.data.status===0){ + this.setState({ + target_id:null, + newec_course_idbottom:response.data.ec_course_id, + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + // Modallists:response.data.message, + // eacoursetype:true, + Modallists:' ', + meweacoursetype:false, + achievement_methods:undefined, + eacoursesavetypes:false, + newshowredvalue:false, + ismanager:response.data.is_manager + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.EvaluationsSaveonloadgetdata(response.data.ec_course_id); + this.getNavigationData(ec_course_id); + + }else if(response.data.status===-1){ + this.setState({ + buttomSaveCourseEvaluationsbottom:this.SaveCourseEvaluationsbottom, + Modallists:response.data.message, + eacoursetype:true, + }) + } + }).catch((error) => { + console.log(error) + }) + } + CancelecCourseEvaluationsbottom=()=>{ + this.setState({ + achievement_methods:undefined, + target_id:null, + methodologytype:false, + Modallists:' ', + meweacoursetype:false, + eacoursesavetypes:false, + newshowredvalue:false, + percentagetype:false + }) + // $("#ecCourseEvaluationsbottomsubmit").hide(); + // $("#SystemParametersbottom").hide(); + this.getec_course_achievement_methods(); + } + + selectsonFocuslist=(e,key)=>{ + let value =e.course_select_value; + let {evaluation_subitems_list,totalevaluations_list,achievement_methods} = this.state; + let newachievement_methods=achievement_methods; + let newlist=new Object (); + let location=key; + let list=totalevaluations_list.evaluations_list; + this.setState({ + evaluations_lists: evaluation_subitems_list[value], + evaluation_subitems_lists: evaluation_subitems_list[value][0] + }); + + if(newachievement_methods.length===0){ + for(var i=0; i0){ + if(newachievement_methods[location]===undefined){ + newachievement_methods.push(newlist) + } + for(var i=0; i{ + this.setState({ + eacoursetype:false + }) + } + render() { + const Option = Select.Option; + let {schooldata,achievement_list,spinningstate,evaluations_list,evaluations_lists,newec_course_target_id,achievement_methods,ec_course_target_name,buttomSaveCourseEvaluationsbottom,sequenceid,target_id, + titlemessages, + Modallists, + eacoursetype, + eacoursesavetypes, + methodologytype, + newec_course_idbottom, + meweacoursetype, + percentagetype, + ismanager + } = this.state; + return ( +
    +
    + +
    +
    {Modallists}
    +
    +
    + 取消 + 确定 +
    +
    + + {/*导航*/} + {/*
    */} + + {/*

    */} + {/*课程列表 > */} + {/* {schooldata.ec_course_name} 课程考核方式与数据来源*/} + {/*/!* *!/*/} + {/*/!* 导出培养目标 *!/*/} + {/*导出策略*/} + {/*

    */} + + {/*
    */} + {/*课程考核标准*/} + {/*(请在完成配置后,使用各项成绩导入模板,将本学年所有参与的学生成绩数据导入系统)*/} + {/*在线课堂:{course_name}*/} + {/*导入课堂数据*/} + {/*
    */} + + {/*
    */} + + + {/*
    */} + + {/*

    */} + {/* 课程体系 >*/} + {/* {schooldata.ec_course_name} */} + {/*

    请结合本课程的教学情况,修改说明每个课程目标的评价环节和评估方式 window.elasticLayer(3533)}>查看详情
    */} + + {/* /!*课程考核方式与数据来源*!/*/} + {/* /!* *!/*/} + {/* /!* 导出培养目标 *!/*/} + {/* */} + {/* 导出评价方法*/} + {/* */} + {/*

    */} + + {/*
    */} + {/* /!*课程目标达成方法*!/*/} + {/* 1.课程目标*/} + {/* 2.课程考核方式与数据来源*/} + {/* 3.成绩等级设置*/} + {/* 4.课程目标评价方法*/} + {/* 5.课程达成评价结果*/} + {/* (各环节平均得分*占比)之和/(各环节总分*占比)之和*/} + {/*
    */} + + {/*
    */} + +
    + +

    + 课程目标 + 评价环节 + 数据内容 + + 操作 + + 评价占比 + 支撑总分值 +

    + + { + achievement_list.length===0?}/>:achievement_list.map((item,key)=>{ + return( +
    + { + item.target_evaluate_data.length===0? +
  • +
    + {key+1} + + + + + + + + +
    +
    + +
    +
    +
    + + + +
    +
    + + +
    +
    + +
    +
    + + {/* 修改start*/} +
    +
    + {/*
    */} +
    +
    + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
    +
    + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + return( +
    +
    + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} id={itemkey} style={{ width: '11%' }} placeholder="请输入占比"/> + % + +
    + + + + + + +
    +
    +
    +
    +
    + ) + }) + } + {Modallists} +
    +
    保存
    +
    取消
    +
    +
    +
    + {/* 修改end*/} + + + +
  • + :item.target_evaluate_data.map((i,k)=>{ + return( +
  • +
    + {key-k===key?key+1:""} + + + {i.evaluate_name} + + + { + i.evaluation_relates_data.map((y,e)=>{ + return( +
    {y.evaluation_relates_name+" "}
    + ) + }) + } +
    + { + key-k===key? +
    +
    + +
    +
    +
    : + +
    +
    + +
    +
    +
    + } + + + +
    {i.percentage+"%"}
    +
    + + +
    {i.score}
    +
    + +
    +
    + {/* 修改start*/} +
    +
    +
    +
    + {/* 课程目标{sequenceid}:{ec_course_target_name} */} + 课程目标{key+1}:{ec_course_target_name} +
    +
    + { + achievement_methods===undefined?" ":achievement_methods.map((item,itemkey)=>{ + + return( +
    +
    + 评价环节 + + + + + + + + + + 100&&eacoursesavetypes===true||percentagetype===true?"bor-red": ""} + onInput={this.handevaluation_CoursePercentag.bind(this)} + id={itemkey} style={{ width: '11%' }} + placeholder="请输入占比"/> + % + +
    + + + + + + +
    +
    +
    +
    +
    + ) + }) + } + {Modallists} +
    +
    保存
    +
    取消
    +
    +
    +
    + {/* 修改end*/} + +
  • + + ) + + }) + } +
    + ) + }) + } +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( EcCourseEvaluationsbottom ) ); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecCourseSupports.js b/public/react/src/modules/ecs/subroute/ecCourseSupports.js deleted file mode 100644 index e5f5b6ccd..000000000 --- a/public/react/src/modules/ecs/subroute/ecCourseSupports.js +++ /dev/null @@ -1,656 +0,0 @@ -import React, { Component } from 'react'; - -import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; - -import classNames from 'classnames' - -import axios from 'axios'; - -import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; - -import { SnackbarHOC } from 'educoder' - -import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd'; - -import EcTitleCourseEvaluations from '../ecTitle/ecTitle' - -import 'antd/dist/antd.css'; - -import '../css/ecCourseSupports.css'; - -const $ = window.$; -class ecCourseSupports 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 jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; - axios.get(jol, { - withCredentials: true, - }) - .then((response) => { - if(response.status===200){ - // if(response.data.allow_visit===false){ - // window.location.href="/403" - // } - this.setState({ - schooldata:response.data - }) - } - }) - .catch(function (error) { - console.log(error); - }); - - - const url = `/ec_course_supports?ec_year_id=`+ec_year_id; - axios.get(url, { - withCredentials: true, - }) - .then((response) => { - if(response.status===200){ - this.setState({ - data:response.data - }) - } - if(response.data.course_support_data.length===0){ - this.setState({ - Supportstype:true, - Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据' - }) - } - }) - .catch(function (error) { - console.log(error); - }); - - // this.setState({ - // data:{course_count: 14, - // course_support_data: [ - // {course_data: [{ - // name: "军事课堂", - // top_relation: true, - // weigths: 0.1 - // }, { - // name: "大学生心理健康教育", - // top_relation: true, - // weigths: 0.2 - // }], - // ec_graduation_subitem_id: 2, - // num_total: 2, - // sequence_num: "1-1", - // weights_total: 0.30000000000000004, - // }, - // ], - // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", - // ec_year_id: 1, - // max_support_count: 12, - // subitems_count: 7, - // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" - // } - // }) - - } - 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, { - withCredentials: true, - }) - .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{ - 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{ - 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;j1){ - 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{ - - 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 { - - 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( -
    支撑课程 -
    (权值) -
    -
    ) - } - return res - } - - return ( -
    - -
    -
    {Supportslist}
    -
    - -
    - - -
    - - - -
    - -
    - 课程体系对毕业要求的支撑 - {/* 导出培养目标 */} - - 导出课程体系支撑矩阵 - -
    用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 window.elasticLayer(3534)} >查看详情
    - -
    -
    - 毕业要求指标点({data.subitems_count} - 课程体系({data.course_count} -
    - -
    - -
    - -

    1200? 140*data.max_support_count : 1200+"px"}}> - 毕业要求指标点 - {list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)} - 合计 -

    -
    - { - data.course_support_data===undefined? }/>:data.course_support_data.map((item,key)=>{ - - return ( -
  • 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}> - - {item.sequence_num} - - - - { - item.course_data.map((t,kes)=>{ - return( - -
    {t.name.length>12?t.name.substring(0, 10)+"...":t.name}
    -
    ({t.weigths})
    -
    - ) - - }) - } - - -
    -
    -
    {item.num_total===0?" ":item.num_total}
    -
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    -
    -
    - {data.is_manager===false?"": - - } -
    -
    - -
    - -

    - -

    - 指标点 {index} - 支撑课程 - - 权重(∑=1) - (精确到两位小数) - - 关联度最高 -

    - -
    - - { - editcourse.map((it,key)=>{ - - return( -
    - - - - -
    - -
    - - - - -
    - - - -
    - -
    - ) - }) - } - -
    - {Supportslist} -
    - 合计: {editcourse.length} - 合计: {editnum} -
    - -
    -
    保存
    -
    取消
    -
    - -

    - - -
  • - ) - }) - } -
    -
    - -
    -
    - ); - } -} - -export default SnackbarHOC() ( TPMIndexHOC ( ecCourseSupports ) ); - diff --git a/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js b/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js new file mode 100644 index 000000000..0523e0e24 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js @@ -0,0 +1,656 @@ +import React, { Component } from 'react'; + +import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; + +import classNames from 'classnames' + +import axios from 'axios'; + +import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd'; + +import EcTitleCourseEvaluations from '../../ecTitle/ecTitle' + +import 'antd/dist/antd.css'; + +import '../../css/ecCourseSupports.css'; + +const $ = window.$; +class EcCourseSupports 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 jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; + axios.get(jol, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + }) + .catch(function (error) { + console.log(error); + }); + + + const url = `/ec_course_supports?ec_year_id=`+ec_year_id; + axios.get(url, { + withCredentials: true, + }) + .then((response) => { + if(response.status===200){ + this.setState({ + data:response.data + }) + } + if(response.data.course_support_data.length===0){ + this.setState({ + Supportstype:true, + Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据' + }) + } + }) + .catch(function (error) { + console.log(error); + }); + + // this.setState({ + // data:{course_count: 14, + // course_support_data: [ + // {course_data: [{ + // name: "军事课堂", + // top_relation: true, + // weigths: 0.1 + // }, { + // name: "大学生心理健康教育", + // top_relation: true, + // weigths: 0.2 + // }], + // ec_graduation_subitem_id: 2, + // num_total: 2, + // sequence_num: "1-1", + // weights_total: 0.30000000000000004, + // }, + // ], + // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", + // ec_year_id: 1, + // max_support_count: 12, + // subitems_count: 7, + // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" + // } + // }) + + } + 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, { + withCredentials: true, + }) + .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{ + 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{ + 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;j1){ + 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{ + + 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 { + + 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( +
    支撑课程 +
    (权值) +
    +
    ) + } + return res + } + + return ( +
    + +
    +
    {Supportslist}
    +
    + +
    + + +
    + + + +
    + +
    + 课程体系对毕业要求的支撑 + {/* 导出培养目标 */} + + 导出课程体系支撑矩阵 + +
    用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 window.elasticLayer(3534)} >查看详情
    + +
    +
    + 毕业要求指标点({data.subitems_count} + 课程体系({data.course_count} +
    + +
    + +
    + +

    1200? 140*data.max_support_count : 1200+"px"}}> + 毕业要求指标点 + {list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)} + 合计 +

    +
    + { + data.course_support_data===undefined? }/>:data.course_support_data.map((item,key)=>{ + + return ( +
  • 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}> + + {item.sequence_num} + + + + { + item.course_data.map((t,kes)=>{ + return( + +
    {t.name.length>12?t.name.substring(0, 10)+"...":t.name}
    +
    ({t.weigths})
    +
    + ) + + }) + } + + +
    +
    +
    {item.num_total===0?" ":item.num_total}
    +
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    +
    +
    + {data.is_manager===false?"": + + } +
    +
    + +
    + +

    + +

    + 指标点 {index} + 支撑课程 + + 权重(∑=1) + (精确到两位小数) + + 关联度最高 +

    + +
    + + { + editcourse.map((it,key)=>{ + + return( +
    + + + + +
    + +
    + + + + +
    + + + +
    + +
    + ) + }) + } + +
    + {Supportslist} +
    + 合计: {editcourse.length} + 合计: {editnum} +
    + +
    +
    保存
    +
    取消
    +
    + +

    + + +
  • + ) + }) + } +
    +
    + +
    +
    + ); + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( ecCourseSupports ) ); + From 5b3d795f75fe51087cbdf317f86760a448f6df65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Tue, 17 Sep 2019 17:31:11 +0800 Subject: [PATCH 09/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/ecs/curriculum/Curriculum.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index e91ff9eb4..328ef6811 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -200,7 +200,7 @@ class Curriculum extends Component { 导出评价详情 - 计算 :titine===4? From 17afca9951ff7c41b4c43437206ab1b1be6242a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Tue, 17 Sep 2019 17:32:30 +0800 Subject: [PATCH 10/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/ecs/curriculum/Curriculum.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index 328ef6811..4bfe97508 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -135,7 +135,7 @@ class Curriculum extends Component { 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); + // console.log(titine); return (
    From 96f4749fac27ea1cc63abd5eb25b3193b6fb2137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Tue, 17 Sep 2019 17:55:52 +0800 Subject: [PATCH 11/23] =?UTF-8?q?=E8=AF=BE=E7=A8=8B=E4=BD=93=E7=B3=BBvs?= =?UTF-8?q?=E6=AF=95=E8=AE=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/package.json | 2 +- public/react/src/AppConfig.js | 9 +- .../CourseSupports/ecCourseSupports.css | 352 ++++++++++ .../ecs/EcSetting/CourseSupports/index.js | 638 ++++++++++++++++++ .../react/src/modules/ecs/EcSetting/index.js | 6 + 5 files changed, 1002 insertions(+), 5 deletions(-) create mode 100644 public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css create mode 100644 public/react/src/modules/ecs/EcSetting/CourseSupports/index.js diff --git a/public/react/package.json b/public/react/package.json index 8d7362c28..e91e61f03 100644 --- a/public/react/package.json +++ b/public/react/package.json @@ -5,7 +5,7 @@ "dependencies": { "@icedesign/base": "^0.2.5", "@novnc/novnc": "^1.1.0", - "antd": "^3.20.1", + "antd": "^3.23.2", "array-flatten": "^2.1.2", "autoprefixer": "7.1.6", "axios": "^0.18.0", diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 5d2373e84..0d5c137ae 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -42,10 +42,11 @@ export function initAxiosInterceptors(props) { // proxy = "http://testbdweb.trustie.net" // proxy = "http://testbdweb.educoder.net" // proxy = "https://testeduplus2.educoder.net" - proxy="http://47.96.87.25:48080" - // wy - proxy="https://pre-newweb.educoder.net" - proxy="https://test-newweb.educoder.net" + // proxy="http://47.96.87.25:48080" + // // wy + // proxy="https://pre-newweb.educoder.net" + // proxy="https://test-newweb.educoder.net" + proxy="http://192.168.2.63:3001"; // wy // proxy="http://192.168.2.63:3001" diff --git a/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css b/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css new file mode 100644 index 000000000..3f1dc000a --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/CourseSupports/ecCourseSupports.css @@ -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; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js new file mode 100644 index 000000000..60c573445 --- /dev/null +++ b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js @@ -0,0 +1,638 @@ +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 jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; + // axios.get(jol, { + // withCredentials: true, + // }) + // .then((response) => { + // if(response.status===200){ + // // if(response.data.allow_visit===false){ + // // window.location.href="/403" + // // } + // this.setState({ + // schooldata:response.data + // }) + // } + // }) + // .catch(function (error) { + // console.log(error); + // }); + + + 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); + }); + + // this.setState({ + // data:{course_count: 14, + // course_support_data: [ + // {course_data: [{ + // name: "军事课堂", + // top_relation: true, + // weigths: 0.1 + // }, { + // name: "大学生心理健康教育", + // top_relation: true, + // weigths: 0.2 + // }], + // ec_graduation_subitem_id: 2, + // num_total: 2, + // sequence_num: "1-1", + // weights_total: 0.30000000000000004, + // }, + // ], + // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", + // ec_year_id: 1, + // max_support_count: 12, + // subitems_count: 7, + // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" + // } + // }) + + } + 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{ + 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{ + 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;j1){ + 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{ + + 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 { + + 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( +
    支撑课程 +
    (权值) +
    +
    ) + } + return res + } + + return ( +
    + +
    +
    {Supportslist}
    +
    + +
    + + +
    + + + +
    + +
    + 课程体系对毕业要求的支撑 + {/* 导出培养目标 */} + + 导出课程体系支撑矩阵 + +
    用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 window.elasticLayer(3534)} >查看详情
    + +
    +
    + 毕业要求指标点({data.subitems_count} + 课程体系({data.course_count} +
    + +
    + +
    + +

    1200? 140*data.max_support_count : 1200+"px"}}> + 毕业要求指标点 + {list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)} + 合计 +

    +
    + { + data.graduation_subitems===undefined? }/>:data.graduation_subitems.map((item,key)=>{ + + return ( +
  • 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}> + + {item.sequence_num} + + + + { + item.course_supports.map((t,kes)=>{ + return( + +
    {t.name.length>12?t.name.substring(0, 10)+"...":t.name}
    +
    ({t.weigths})
    +
    + ) + + }) + } + + +
    +
    +
    {item.course_supports.length}
    +
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    +
    +
    + {data.is_manager===false?"": + + } +
    +
    + +
    + +

    + +

    + 指标点 {index} + 支撑课程 + + 权重(∑=1) + (精确到两位小数) + + 关联度最高 +

    + +
    + + { + editcourse.map((it,key)=>{ + + return( +
    + + + + +
    + +
    + + + + +
    + + + +
    + +
    + ) + }) + } + +
    + {Supportslist} +
    + 合计: {editcourse.length} + 合计: {editnum} +
    + +
    +
    保存
    +
    取消
    +
    + +

    + + +
  • + ) + }) + } +
    +
    + +
    +
    + ); + } +} + +export default CourseSupports ; + diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js index 4f27acb2a..99e4c8bea 100644 --- a/public/react/src/modules/ecs/EcSetting/index.js +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -11,6 +11,8 @@ const { Step } = Steps; const TrainingObjective = CustomLoadable(() => import('./TrainingObjective/index')) const GraduationRequirement = CustomLoadable(() => import('./GraduationRequirement/index')) +const CourseSupports = CustomLoadable(() => import('./CourseSupports/index')) + 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"]; @@ -101,6 +103,10 @@ class EcSetting extends React.Component { render={ (props) => () }> () }> + + + () }> ) } From 098f4ced0675ea363370880957d51e0004460136 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 18 Sep 2019 09:04:48 +0800 Subject: [PATCH 12/23] ecs: fix weigths weight && fix style --- app/models/ec_course_support.rb | 2 ++ app/models/ec_course_target.rb | 3 ++- .../shared/_ec_graduation_subitem.json.jbuilder | 1 + public/react/src/modules/ecs/EcSetting/index.scss | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/models/ec_course_support.rb b/app/models/ec_course_support.rb index c7865f73c..518fc1385 100644 --- a/app/models/ec_course_support.rb +++ b/app/models/ec_course_support.rb @@ -1,6 +1,8 @@ class EcCourseSupport < ApplicationRecord default_scope { order(position: :asc) } + alias_attribute :weights, :weigths + belongs_to :ec_course belongs_to :ec_graduation_subitem diff --git a/app/models/ec_course_target.rb b/app/models/ec_course_target.rb index 9b93cb73c..b13c81059 100644 --- a/app/models/ec_course_target.rb +++ b/app/models/ec_course_target.rb @@ -1,4 +1,3 @@ -# TODO:: change table column :weigths => :weight class EcCourseTarget < ApplicationRecord belongs_to :ec_course @@ -8,6 +7,8 @@ class EcCourseTarget < ApplicationRecord has_many :ec_course_achievement_methods, dependent: :destroy has_many :ec_achievement_evaluation_relates, dependent: :destroy + alias_attribute :weight, :weigths + validates :content, presence: true validates :standard_grade, numericality: { only_integer: true, greater_than: 0 } validates :weight, presence: true, numericality: { less_than_or_equal_to: 1, greater_than_or_equal_to: 0 } diff --git a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder index 1ffe12ec4..aee77c5b7 100644 --- a/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder +++ b/app/views/ecs/graduation_course_supports/shared/_ec_graduation_subitem.json.jbuilder @@ -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.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) diff --git a/public/react/src/modules/ecs/EcSetting/index.scss b/public/react/src/modules/ecs/EcSetting/index.scss index 8c8d7cbd3..7fcd80880 100644 --- a/public/react/src/modules/ecs/EcSetting/index.scss +++ b/public/react/src/modules/ecs/EcSetting/index.scss @@ -15,7 +15,7 @@ background: #fff; .ant-steps-item { - flex: unset; + flex: unset !important; &-container { margin-left: 0; From 21851b87f73a5dcad771e412008d2e98bce20360 Mon Sep 17 00:00:00 2001 From: hjm <63528605@qq.com> Date: Wed, 18 Sep 2019 09:22:48 +0800 Subject: [PATCH 13/23] =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/AppConfig.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/public/react/src/AppConfig.js b/public/react/src/AppConfig.js index 0d5c137ae..5f30a26a8 100644 --- a/public/react/src/AppConfig.js +++ b/public/react/src/AppConfig.js @@ -39,17 +39,13 @@ export function initAxiosInterceptors(props) { // TODO 读取到package.json中的配置? var proxy = "http://localhost:3000" - // proxy = "http://testbdweb.trustie.net" - // proxy = "http://testbdweb.educoder.net" - // proxy = "https://testeduplus2.educoder.net" - // proxy="http://47.96.87.25:48080" - // // wy + // proxy="https://pre-newweb.educoder.net" // proxy="https://test-newweb.educoder.net" proxy="http://192.168.2.63:3001"; // wy - // proxy="http://192.168.2.63:3001" + proxy="http://192.168.2.63:3001" // 在这里使用requestMap控制,避免用户通过双击等操作发出重复的请求; // 如果需要支持重复的请求,考虑config里面自定义一个allowRepeat参考来控制 From 729fd61261b7095ead111eeb237b79de9e2b865e Mon Sep 17 00:00:00 2001 From: p31729568 Date: Wed, 18 Sep 2019 11:22:25 +0800 Subject: [PATCH 14/23] ecs: add api --- app/controllers/ecs/reach_evaluations_controller.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/controllers/ecs/reach_evaluations_controller.rb b/app/controllers/ecs/reach_evaluations_controller.rb index 97576447c..25ac24656 100644 --- a/app/controllers/ecs/reach_evaluations_controller.rb +++ b/app/controllers/ecs/reach_evaluations_controller.rb @@ -14,5 +14,13 @@ class Ecs::ReachEvaluationsController < Ecs::BaseController end def create + relations = current_year.ec_graduation_requirements.joins(ec_graduation_subitems: :ec_course_support) + ec_course_ids = relations.pluck('ec_course_supports.ec_course_id').uniq + + EcCourse.where(id: ec_course_ids).each do |ec_course| + Ecs::CalculateCourseEvaluationService.call(ec_course) + end + + render_ok end end From 9b156d2a658739fcda4d22751bb071855e14681a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 09:59:42 +0800 Subject: [PATCH 15/23] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E7=89=88build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/modules/ecs/curriculum/Curriculum.js | 15 ++++++++++++++- .../EcCourseEvaluationsbottom.js | 2 +- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index 4bfe97508..9f4227c28 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -23,11 +23,24 @@ import { } from 'react-router-dom'; import Loadable from 'react-loadable'; import Loading from "../../../Loading"; +const $ = window.$; const Curriculumtwo = Loadable({ loader: () => import('./Curriculumtwo'), loading: Loading, }) -const $ = window.$; +const EcCourseEvaluationsbottom =Loadable({ + loader: () => import('../subroute/ecCourseEvaluations/EcCourseEvaluationsbottom'), + loading: Loading, +}); +const EcCompletionCalculation =Loadable({ + loader: () => import('../subroute/ecCompletion_calculation/EcCompletionCalculation'), + loading: Loading, +}); +const EcCourseSupports=Loadable({ + loader: () => import('../subroute/ecCourseSupports/EcCourseSupports'), + loading: Loading, +}); + class Curriculum extends Component { //课程体系 constructor(props) { diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js index a8b3e19a7..4c49d6a97 100644 --- a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -6,7 +6,7 @@ import classNames from 'classnames' import axios from 'axios'; -import { TPMIndexHOC } from '../../tpm/TPMIndexHOC'; +import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; import { SnackbarHOC } from 'educoder' From 2988dd57ff4f96f0caacee0cd0d3e9515be600b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 10:12:21 +0800 Subject: [PATCH 16/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/ecs/curriculum/Curriculum.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index 9f4227c28..a02eed61e 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -243,10 +243,10 @@ class Curriculum extends Component { render={ (props) => (this.Ontitine(i)}/>) }> {/*课程目标评价方法*/} (this.Ontitine(i)}/>) }> + render={ (props) => (this.Ontitine(i)}/>) }> {/*课程达成评价结果*/} (this.Ontitine(i)}/>) }> + render={ (props) => (this.Ontitine(i)}/>) }>
    From 745a9da7107104aabed2add2b458a5023293dc14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 10:21:55 +0800 Subject: [PATCH 17/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EcCompletionCalculation.js | 3 +- .../ecCourseSupports/EcCourseSupports.js | 656 ------------------ .../subroute/ecStudentList/EcStudentList.js | 430 ++++++++++++ .../subroute/ecStudentList/ecStudentList.css | 44 ++ .../ecs/subroute/ecStudentList/nodata.png | Bin 0 -> 14616 bytes 5 files changed, 475 insertions(+), 658 deletions(-) delete mode 100644 public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js create mode 100644 public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js create mode 100644 public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css create mode 100644 public/react/src/modules/ecs/subroute/ecStudentList/nodata.png diff --git a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js index 14e104e05..7723278a3 100644 --- a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js +++ b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js @@ -497,8 +497,7 @@ class EcCompletionCalculation extends Component {

    { Spintype===true?}/>:"" } - - + { target_list.length===0&&Spintype===false?
  • -- diff --git a/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js b/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js deleted file mode 100644 index 0523e0e24..000000000 --- a/public/react/src/modules/ecs/subroute/ecCourseSupports/EcCourseSupports.js +++ /dev/null @@ -1,656 +0,0 @@ -import React, { Component } from 'react'; - -import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom"; - -import classNames from 'classnames' - -import axios from 'axios'; - -import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; - -import { SnackbarHOC } from 'educoder' - -import { Select,message,Modal,Input,Spin,Icon,Tooltip } from 'antd'; - -import EcTitleCourseEvaluations from '../../ecTitle/ecTitle' - -import 'antd/dist/antd.css'; - -import '../../css/ecCourseSupports.css'; - -const $ = window.$; -class EcCourseSupports 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 jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; - axios.get(jol, { - withCredentials: true, - }) - .then((response) => { - if(response.status===200){ - // if(response.data.allow_visit===false){ - // window.location.href="/403" - // } - this.setState({ - schooldata:response.data - }) - } - }) - .catch(function (error) { - console.log(error); - }); - - - const url = `/ec_course_supports?ec_year_id=`+ec_year_id; - axios.get(url, { - withCredentials: true, - }) - .then((response) => { - if(response.status===200){ - this.setState({ - data:response.data - }) - } - if(response.data.course_support_data.length===0){ - this.setState({ - Supportstype:true, - Supportslist:'数据为空,请去毕业要求——>毕业要求指标点分解列表配置数据' - }) - } - }) - .catch(function (error) { - console.log(error); - }); - - // this.setState({ - // data:{course_count: 14, - // course_support_data: [ - // {course_data: [{ - // name: "军事课堂", - // top_relation: true, - // weigths: 0.1 - // }, { - // name: "大学生心理健康教育", - // top_relation: true, - // weigths: 0.2 - // }], - // ec_graduation_subitem_id: 2, - // num_total: 2, - // sequence_num: "1-1", - // weights_total: 0.30000000000000004, - // }, - // ], - // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", - // ec_year_id: 1, - // max_support_count: 12, - // subitems_count: 7, - // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" - // } - // }) - - } - 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, { - withCredentials: true, - }) - .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{ - 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{ - 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;j1){ - 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{ - - 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 { - - 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( -
    支撑课程 -
    (权值) -
    -
    ) - } - return res - } - - return ( -
    - -
    -
    {Supportslist}
    -
    - -
    - - -
    - - - -
    - -
    - 课程体系对毕业要求的支撑 - {/* 导出培养目标 */} - - 导出课程体系支撑矩阵 - -
    用矩阵图的形式说明本专业课程体系对毕业要求的支撑关系 window.elasticLayer(3534)} >查看详情
    - -
    -
    - 毕业要求指标点({data.subitems_count} - 课程体系({data.course_count} -
    - -
    - -
    - -

    1200? 140*data.max_support_count : 1200+"px"}}> - 毕业要求指标点 - {list(data.max_support_count<5||data.max_support_count===undefined?5:data.max_support_count)} - 合计 -

    -
    - { - data.course_support_data===undefined? }/>:data.course_support_data.map((item,key)=>{ - - return ( -
  • 1134 ? 136*data.max_support_count : 1134+"px",margin: '0px 0px'}}> - - {item.sequence_num} - - - - { - item.course_data.map((t,kes)=>{ - return( - -
    {t.name.length>12?t.name.substring(0, 10)+"...":t.name}
    -
    ({t.weigths})
    -
    - ) - - }) - } - - -
    -
    -
    {item.num_total===0?" ":item.num_total}
    -
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    -
    -
    - {data.is_manager===false?"": - - } -
    -
    - -
    - -

    - -

    - 指标点 {index} - 支撑课程 - - 权重(∑=1) - (精确到两位小数) - - 关联度最高 -

    - -
    - - { - editcourse.map((it,key)=>{ - - return( -
    - - - - -
    - -
    - - - - -
    - - - -
    - -
    - ) - }) - } - -
    - {Supportslist} -
    - 合计: {editcourse.length} - 合计: {editnum} -
    - -
    -
    保存
    -
    取消
    -
    - -

    - - -
  • - ) - }) - } -
    - - - - - ); - } -} - -export default SnackbarHOC() ( TPMIndexHOC ( ecCourseSupports ) ); - diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js new file mode 100644 index 000000000..37dcb0b31 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js @@ -0,0 +1,430 @@ +import React, { Component } from 'react'; + +import axios from 'axios'; +import { Spin } from 'antd'; + +import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; + +import { SnackbarHOC } from 'educoder' + +import { Pagination,Upload,Modal,Checkbox } from 'antd'; + +import EcTitleCourseEvaluations from '../../ecTitle/ecTitle' + +import 'antd/dist/antd.css'; + +import './ecStudentList.css'; + +const $ = window.$; + +class EcStudentList extends Component { + constructor(props) { + super(props) + this.state={ + schooldata:{}, + majorschoollist:undefined, + titlemessage:"提示", + ecComponentState:"ecStudentList", + visible:false, + Modallist:'', + Modallisttypes:0, + studentall:false, + student_id:undefined, + Modallisttypess:0, + ismanager:false, + isSpin:false + } + } + componentDidMount(){ + window.document.title = '学生列表'; + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + + const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+year_id; + axios.get(jol, { + withCredentials: true, + }).then((response) => { + + if(response.status===200){ + // if(response.data.allow_visit===false){ + // window.location.href="/403" + // } + this.setState({ + schooldata:response.data + }) + } + }) + .catch(function (error) { + console.log(error); + }); + + const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data'; + axios.get(url, { + withCredentials: true, + }).then((response) => { + if(response.status===200){ + this.setState({ + majorschoollist:response.data, + ismanager:response.data.ismanager, + }) + } + }) + .catch(function (error) { + console.log(error); + }); + // let majorschoollist={ + // ec_students: [{index: 1, student_name: "同意", student_id: "s20111458"}, + // {index: 1, student_name: "同意", student_id: "s20111458"}, + // {index: 2, student_name: "涛哥", student_id: "2011554f4"}, + // {index: 3, student_name: "例如", student_id: "20154787b"}, + // {index: 4, student_name: "问问", student_id: "201548580014"}, + // {index: 5, student_name: "嗯嗯", student_id: "2015748912321234"}, + // {index: 6, student_name: "让人", student_id: "20157456"}, + // {index: 7, student_name: "方法", student_id: "20159658"}, + // {index: 8, student_name: "全球", student_id: "20159632"}, + // {index: 9, student_name: "是说", student_id: "20154512"}, + // {index: 10, student_name: "谷歌", student_id: "20157932"}, + // {index: 11, student_name: "版本", student_id: "20159635"}, + // {index: 12, student_name: "捏捏", student_id: "20153451"}, + // ], + // import_url: "/ec_major_schools/3/academic_years/10/import_students", + // show_name: true, + // template_url: "/attachments/download/227528/01_学生列表导入模板.xls", + // total_page: 1 + // } + // this.setState({ + // majorschoollist:majorschoollist + // }) + } + uploadcomponentDidMount(){ + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data'; + axios.get(url, { + withCredentials: true, + }).then((response) => { + if(response.status===200){ + this.setState({ + majorschoollist:response.data, + ismanager:response.data.ismanager, + }) + } + }) + .catch(function (error) { + console.log(error); + }); + } + + + windowsgoblack=()=>{ + window.history.go(-1) + } + + + uploadfile=(file)=>{ + this.setState({isSpin:true}) + let {majorschoollist}=this.state; + let Url =majorschoollist.import_url; + const form = new FormData(); + form.append('file', file.file); + axios.post(Url,form + ).then((response) => { + if(response.data.status===1){ + // message.success('已成功导入'+response.data.count+"条数据!"); + this.setState({ + // titlemessage: response.data.message+"(支撑关系变更)", + Modallist: '已成功导入'+response.data.count+"条数据!", + Modallisttype:true, + Modallisttypes:1, + isSpin:false + }) + }else if(response.data.status===0){ + // message.warning(response.data.message); + this.setState({ + // titlemessage: response.data.message+"(支撑关系变更)", + Modallist:response.data.message, + Modallisttype:true, + Modallisttypes:0, + isSpin:false + }) + } + }).catch((error) => { + console.log(error) + }) + } + hidemodeldelete=()=>{ + let {Modallisttypes}=this.state; + this.setState({ + Modallisttype:false, + Modallist:'', + Modallisttypess:0 + }) + if(Modallisttypes===1){ + // window.location.reload(); + this.uploadcomponentDidMount(); + } + } + + showecStudentList=(page)=>{ + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data?page='+page; + axios.get(url, { + withCredentials: true, + }).then((response) => { + if(response.status===200){ + this.setState({ + majorschoollist:response.data, + ismanager:response.data.ismanager, + }) + } + }).catch(function (error) { + console.log(error); + }); + } + + onChangestudentall=(e)=>{ + let {majorschoollist}=this.state; + let mewmajorschoollist=majorschoollist + for(var i=0; i{ + let {majorschoollist,studentall}=this.state; + let mewmajorschoollist=majorschoollist; + let newstudentall=studentall; + if(e.target.checked===false){ + newstudentall=false + } + for(var i=0; i{ + let {majorschoollist,studentall} =this.state; + let studentalltype=0 + for(var i=0; i{ + let {majorschoollist,studentall} =this.state; + let major_id=this.props.match.params.major_id; + let year_id=this.props.match.params.year_id; + let newstudent_id=[]; + if(studentall===false){ + for(var i=0; i { + if(response.data.status===1){ + this.setState({ + // Modallist: "删除成功!", + // Modallisttype:true, + Modallisttypes:1, + Modallisttypess:0 + }) + this.hidemodeldelete(); + } + }).catch((error) => { + console.log(error) + }) + } + + render() { + let {schooldata, + majorschoollist, + Modallisttype, + titlemessage, + Modallist, + studentall, + student_id, + Modallisttypess, + ismanager + }=this.state; + // ec_students: [] + // import_url: "/ec_major_schools/:1/academic_years/:1/import_students" + // template_url: "javascript:void(0);" + // total_page: 0 + const uploadProps = { + name: 'file', + + onPreview(file) { + // dispatch({ type: `${nameSpace}/updateState`, payload: { uploadPreviewVisible: true, uploadPreviewImage: file.url || file.thumbUrl } }); + }, + onChange(file) { + // dispatch({ type: `${nameSpace}/updateState`, payload: { fileList: fileList } }); + }, + onRemove(option) { + }, + customRequest: file => { + this.uploadfile(file) + } + } + return ( +
    + +
    +
    {Modallist}
    +
    +
    + 取消 + { + Modallisttypess===0?确定:确定 + } + +
    +
    +
    + + +
    + 学生列表 + 返回 +
    + +
    + +
    学生列表( + {majorschoollist===undefined?"":majorschoollist.total_student} + ) +
    提供模板支持导入学生信息(请先下载模板) window.elasticLayer(3533)}>查看详情
    +
    + +
    + {ismanager===false?"": + 请使用导入模板(点击下载),将本学年所有参与的学生导入系统,以便录入教学活动相关数据 + } + + {ismanager===false?"": + 导入 + } + +
    + +
    + {ismanager===false?"":
    + 删除 +
    } +
    + +
    +

    + + + 序号 + + 姓名 + 学号 +

    + + +
      + { + majorschoollist===undefined? +
      +

      +

      学生数据为空,请导入数据

      +
      + :majorschoollist.ec_students.length===0? +
      +

      +

      学生数据为空,请导入数据

      +
      :majorschoollist.ec_students.map((item,key)=>{ + // console.log(item) + return( +
    • + + + {item.index} + + {item.student_name} + {item.student_id} +
    • + ) + }) + } + +
    + +
    + { + majorschoollist===undefined?"":majorschoollist.total_page===0||majorschoollist.total_student<51?"": + } +
    +
    +
    +
    +
    + +
    + + ) + + } +} + +export default SnackbarHOC() ( TPMIndexHOC ( EcStudentList ) ); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css b/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css new file mode 100644 index 000000000..0dfc22b99 --- /dev/null +++ b/public/react/src/modules/ecs/subroute/ecStudentList/ecStudentList.css @@ -0,0 +1,44 @@ +.pagelistStudentList{ + position: absolute; + padding-left: 40%; +} + +.relative{ + position: relative; +} +.changestudent{ + position: absolute; + top: 13px; + left: 50px; +} +.changestudents{ + position: absolute; + top: -1px; + left: 50px; +} +.padbottom{ + padding-bottom: 0px; +} + +.deletelist{ + margin-top: 10px; + margin-bottom: 10px; +} + +.deletelist:hover{ + color:#afafaf !important; +} + +.deletebth{ + width:64px; + height:24px; + border:1px solid #afafaf; + border-radius:2px; + color:#afafaf; + background:#fff; + line-height:24px; +} + +.mt60{ + margin-top:60px; +} \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/nodata.png b/public/react/src/modules/ecs/subroute/ecStudentList/nodata.png new file mode 100644 index 0000000000000000000000000000000000000000..15a9e522f8d405897fa7e8108b4274ad7ba784f6 GIT binary patch literal 14616 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 E0}_S}fB*mh literal 0 HcmV?d00001 From c3eb389e9b16aa8d9a3e3b84c67f1458917cf5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 10:49:05 +0800 Subject: [PATCH 18/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../react/src/modules/ecs/EcSetting/index.js | 40 +++++++++++++++---- .../src/modules/ecs/curriculum/Curriculum.js | 5 +-- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js index 4dd6318bf..4b587f26f 100644 --- a/public/react/src/modules/ecs/EcSetting/index.js +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -6,16 +6,31 @@ import axios from 'axios'; import './index.scss'; import CustomLoadable from "../../../CustomLoadable"; -import Curriculum from "../../../modules/ecs/curriculum/Curriculum" +import Loadable from 'react-loadable'; +import Loading from "../../../Loading"; const { Step } = Steps; - -const TrainingObjective = CustomLoadable(() => import('./TrainingObjective/index')) -const GraduationRequirement = CustomLoadable(() => import('./GraduationRequirement/index')) -const CourseSupports = CustomLoadable(() => import('./CourseSupports/index')) - - 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) { @@ -50,7 +65,11 @@ class EcSetting extends React.Component { let type = stepTypes[stepIndex]; this.setState({ stepIndex: stepIndex }); - this.props.history.push(`/ecs/major_schools/${majorId}/years/${yearId}/${type}`); + 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 = () => { @@ -101,6 +120,11 @@ class EcSetting extends React.Component { () }> + + + {/*学生*/} + () }> {/*课程体系*/} () }> diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index a02eed61e..bf4c1cbc8 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -36,10 +36,7 @@ const EcCompletionCalculation =Loadable({ loader: () => import('../subroute/ecCompletion_calculation/EcCompletionCalculation'), loading: Loading, }); -const EcCourseSupports=Loadable({ - loader: () => import('../subroute/ecCourseSupports/EcCourseSupports'), - loading: Loading, -}); + class Curriculum extends Component { //课程体系 From a069c86b26fc2d80a14b788b6b79d62fcf3c838f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=98=8E?= <775174143@qq.com> Date: Thu, 19 Sep 2019 10:57:06 +0800 Subject: [PATCH 19/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/react/src/modules/ecs/EcSetting/index.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/public/react/src/modules/ecs/EcSetting/index.js b/public/react/src/modules/ecs/EcSetting/index.js index 4b587f26f..d85d10aec 100644 --- a/public/react/src/modules/ecs/EcSetting/index.js +++ b/public/react/src/modules/ecs/EcSetting/index.js @@ -120,6 +120,8 @@ class EcSetting extends React.Component { () }> + () }> {/*学生*/} @@ -129,14 +131,11 @@ class EcSetting extends React.Component { () }> {/*课程体系VS毕业要求*/} - () }> - () }> - - () }> + + + ) } From f3984a28fee92f74724e68b5af24925e7b975391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 11:16:37 +0800 Subject: [PATCH 20/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../EcCompletionCalculation.js | 16 ++++---- .../EcCourseEvaluationsbottom.js | 14 +++---- .../subroute/ecStudentList/EcStudentList.js | 37 +++---------------- 3 files changed, 21 insertions(+), 46 deletions(-) diff --git a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js index 7723278a3..c24e7c13c 100644 --- a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js +++ b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js @@ -3,7 +3,7 @@ import classNames from 'classnames' import axios from 'axios'; -import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; +// import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; import { SnackbarHOC } from 'educoder' @@ -431,12 +431,12 @@ class EcCompletionCalculation extends Component {
    - + {/**/}
    @@ -809,5 +809,5 @@ class EcCompletionCalculation extends Component { } } -export default SnackbarHOC() ( TPMIndexHOC ( EcCompletionCalculation ) ); +export default SnackbarHOC() (EcCompletionCalculation); diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js index 4c49d6a97..5d0488b2e 100644 --- a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -6,7 +6,7 @@ import classNames from 'classnames' import axios from 'axios'; -import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; +// import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; import { SnackbarHOC } from 'educoder' @@ -703,11 +703,11 @@ class EcCourseEvaluationsbottom extends Component { {/*
    */} {/*
    */} - + {/**/} {/*
    */} @@ -1036,4 +1036,4 @@ class EcCourseEvaluationsbottom extends Component { } } -export default SnackbarHOC() ( TPMIndexHOC ( EcCourseEvaluationsbottom ) ); \ No newline at end of file +export default SnackbarHOC() (EcCourseEvaluationsbottom); \ No newline at end of file diff --git a/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js index 37dcb0b31..312bfeecf 100644 --- a/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js +++ b/public/react/src/modules/ecs/subroute/ecStudentList/EcStudentList.js @@ -5,7 +5,7 @@ import { Spin } from 'antd'; import { TPMIndexHOC } from '../../../tpm/TPMIndexHOC'; -import { SnackbarHOC } from 'educoder' +import { SnackbarHOC,getImageUrl } from 'educoder' import { Pagination,Upload,Modal,Checkbox } from 'antd'; @@ -21,10 +21,9 @@ class EcStudentList extends Component { constructor(props) { super(props) this.state={ - schooldata:{}, majorschoollist:undefined, titlemessage:"提示", - ecComponentState:"ecStudentList", + // ecComponentState:"ecStudentList", visible:false, Modallist:'', Modallisttypes:0, @@ -40,24 +39,6 @@ class EcStudentList extends Component { let major_id=this.props.match.params.major_id; let year_id=this.props.match.params.year_id; - const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+year_id; - axios.get(jol, { - withCredentials: true, - }).then((response) => { - - if(response.status===200){ - // if(response.data.allow_visit===false){ - // window.location.href="/403" - // } - this.setState({ - schooldata:response.data - }) - } - }) - .catch(function (error) { - console.log(error); - }); - const url ='/ec_major_schools/'+major_id+'/academic_years/'+year_id+'/student_lists_data'; axios.get(url, { withCredentials: true, @@ -267,7 +248,7 @@ class EcStudentList extends Component { } render() { - let {schooldata, + let { majorschoollist, Modallisttype, titlemessage, @@ -322,12 +303,6 @@ class EcStudentList extends Component {
    - -
    学生列表 返回 @@ -381,12 +356,12 @@ class EcStudentList extends Component { { majorschoollist===undefined?
    -

    +

    学生数据为空,请导入数据

    :majorschoollist.ec_students.length===0?
    -

    +

    学生数据为空,请导入数据

    :majorschoollist.ec_students.map((item,key)=>{ // console.log(item) @@ -427,4 +402,4 @@ class EcStudentList extends Component { } } -export default SnackbarHOC() ( TPMIndexHOC ( EcStudentList ) ); \ No newline at end of file +export default SnackbarHOC() (EcStudentList); \ No newline at end of file From a923e232a32d2c4f378d83a64f93f1f541aca902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=A0=91=E6=9E=97?= <904079904@qq.com> Date: Thu, 19 Sep 2019 13:47:31 +0800 Subject: [PATCH 21/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/modules/ecs/curriculum/Curriculum.js | 4 +- .../EcCompletionCalculation.js | 90 +++++++++---------- .../EcCourseEvaluationsbottom.js | 2 +- 3 files changed, 46 insertions(+), 50 deletions(-) diff --git a/public/react/src/modules/ecs/curriculum/Curriculum.js b/public/react/src/modules/ecs/curriculum/Curriculum.js index bf4c1cbc8..3dae260de 100644 --- a/public/react/src/modules/ecs/curriculum/Curriculum.js +++ b/public/react/src/modules/ecs/curriculum/Curriculum.js @@ -238,10 +238,10 @@ class Curriculum extends Component { {/*成绩等级设置*/} (this.Ontitine(i)}/>) }> - {/*课程目标评价方法*/} + {/*4课程目标评价方法*/} (this.Ontitine(i)}/>) }> - {/*课程达成评价结果*/} + {/*5课程达成评价结果*/} (this.Ontitine(i)}/>) }> diff --git a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js index c24e7c13c..4be7c11d3 100644 --- a/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js +++ b/public/react/src/modules/ecs/subroute/ecCompletion_calculation/EcCompletionCalculation.js @@ -438,53 +438,49 @@ class EcCompletionCalculation extends Component { {/* ecpath={"show"}*/} {/*/>*/} -
    - -
    - 课程体系 > - {schooldata.ec_course_name} 达成评价详情 - {/* 导出培养目标 */} -
    系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
    - -
    - -
    - 1.课程目标 - 2.课程考核方式与数据来源 - 3.成绩等级设置 - 4.课程目标评价方法 - 5.课程达成评价结果 - {/* 课程体系: - { - evaluate_result===false?未达成:达成 - } - */} - 计算 - - 导出评价详情 - -
    - -
    + {/*
    */} + {/*
    */} + {/* 课程体系 >*/} + {/* {schooldata.ec_course_name} 达成评价详情*/} + {/* /!* 导出培养目标 *!/*/} + {/*
    系统根据课程目标、课程考核方式与课程目标评价方法,一键计算评价课程目标的达成情况 window.elasticLayer(3533)}>查看详情
    */} + {/*
    */} + {/*
    */} + {/* 1.课程目标*/} + {/* 2.课程考核方式与数据来源*/} + {/* 3.成绩等级设置*/} + {/* 4.课程目标评价方法*/} + {/* 5.课程达成评价结果*/} + {/* /!* 课程体系:*/} + {/* {*/} + {/* evaluate_result===false?未达成:达成*/} + {/* }*/} + {/* *!/*/} + {/* 计算*/} + {/* */} + {/* 导出评价详情*/} + {/* */} + {/*
    */} + {/*
    */}
    diff --git a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js index 5d0488b2e..6e27711b2 100644 --- a/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js +++ b/public/react/src/modules/ecs/subroute/ecCourseEvaluations/EcCourseEvaluationsbottom.js @@ -664,7 +664,7 @@ class EcCourseEvaluationsbottom extends Component { } = this.state; return (
    -
    +
    Date: Thu, 19 Sep 2019 14:26:19 +0800 Subject: [PATCH 22/23] =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ecs/EcSetting/CourseSupports/index.js | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js index 60c573445..e5d413601 100644 --- a/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js +++ b/public/react/src/modules/ecs/EcSetting/CourseSupports/index.js @@ -52,24 +52,6 @@ class CourseSupports extends Component { this.setState({ ec_year_id:ec_year_id }) - // const jol =`/ec_major_schools/get_navigation_data?ec_year_id=`+ec_year_id; - // axios.get(jol, { - // withCredentials: true, - // }) - // .then((response) => { - // if(response.status===200){ - // // if(response.data.allow_visit===false){ - // // window.location.href="/403" - // // } - // this.setState({ - // schooldata:response.data - // }) - // } - // }) - // .catch(function (error) { - // console.log(error); - // }); - const url = `/ec_years/${ec_year_id}/graduation_course_supports.json`; axios.get(url) @@ -90,32 +72,6 @@ class CourseSupports extends Component { console.log(error); }); - // this.setState({ - // data:{course_count: 14, - // course_support_data: [ - // {course_data: [{ - // name: "军事课堂", - // top_relation: true, - // weigths: 0.1 - // }, { - // name: "大学生心理健康教育", - // top_relation: true, - // weigths: 0.2 - // }], - // ec_graduation_subitem_id: 2, - // num_total: 2, - // sequence_num: "1-1", - // weights_total: 0.30000000000000004, - // }, - // ], - // course_url: "/ec_major_schools/1/academic_years/1/ec_course_setting", - // ec_year_id: 1, - // max_support_count: 12, - // subitems_count: 7, - // subitems_url: "/ec_major_schools/1/academic_years/1/graduation_requirement" - // } - // }) - } componentDidMount(){ this.setState({ @@ -525,7 +481,7 @@ class CourseSupports extends Component {
    {item.course_supports.length}
    -
    {Math.round(item.weights_total*100)/100===0?" ":(Math.round(item.weights_total*100)/100)}
    +
    {Math.round(item.weights_total*100)/100===0?0:(Math.round(item.weights_total*100)/100)}
    {data.is_manager===false?"": From 5d1e0b2d8e770939c084901d5c5e2845ec88a250 Mon Sep 17 00:00:00 2001 From: p31729568 Date: Thu, 19 Sep 2019 15:56:28 +0800 Subject: [PATCH 23/23] ecs: fix course evaluation api --- app/models/ec_course_student_score.rb | 1 - app/services/ecs/create_course_service.rb | 2 +- .../ecs/query_course_evaluation_service.rb | 29 +++++++++++++++---- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/app/models/ec_course_student_score.rb b/app/models/ec_course_student_score.rb index 5b45e34a9..57d524b46 100644 --- a/app/models/ec_course_student_score.rb +++ b/app/models/ec_course_student_score.rb @@ -1,7 +1,6 @@ class EcCourseStudentScore < ApplicationRecord belongs_to :ec_year_student belongs_to :ec_course - belongs_to :ec_course_target has_many :ec_student_score_targets, dependent: :delete_all end \ No newline at end of file diff --git a/app/services/ecs/create_course_service.rb b/app/services/ecs/create_course_service.rb index dba162189..3e3828c6f 100644 --- a/app/services/ecs/create_course_service.rb +++ b/app/services/ecs/create_course_service.rb @@ -27,7 +27,7 @@ class Ecs::CreateCourseService < ApplicationService private def create_default_score_levels!(ec_course) - EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position) do |worker| + EcScoreLevel.bulk_insert(:ec_course_id, :score, :level, :position, :created_at, :updated_at) do |worker| [ { ec_course_id: ec_course.id, score: 90, level: '优秀', position: 1 }, { ec_course_id: ec_course.id, score: 80, level: '良好', position: 2 }, diff --git a/app/services/ecs/query_course_evaluation_service.rb b/app/services/ecs/query_course_evaluation_service.rb index 8c76da438..22e0ce1f4 100644 --- a/app/services/ecs/query_course_evaluation_service.rb +++ b/app/services/ecs/query_course_evaluation_service.rb @@ -17,12 +17,12 @@ class Ecs::QueryCourseEvaluationService < ApplicationService end def graduation_subitem_evaluations - student_scores = ec_course.ec_course_student_scores.joins(:ec_course_target).group(:ec_course_target_id) + student_scores = ec_course.ec_course_student_scores.joins(ec_student_score_targets: :ec_course_target).group(:ec_course_target_id) student_scores = student_scores.select('AVG(score) as average_score, ec_course_target_id') student_score_map = student_scores.group_by { |item| item.ec_course_target_id } subitem_targets = ec_course.ec_graduation_subitem_course_targets - .includes(ec_graduation_subitem: :ec_graduation_requirement) + .includes(:ec_course_target, ec_graduation_subitem: :ec_graduation_requirement) subitem_targets.group_by(&:ec_graduation_subitem_id).map do |_id, arr| subitem = arr.first.ec_graduation_subitem @@ -37,7 +37,7 @@ class Ecs::QueryCourseEvaluationService < ApplicationService arr.map(&:ec_course_target).uniq.each do |target| target_total_rates += target.weight.to_f - student_score = student_score_map[target.id] + student_score = student_score_map[target.id]&.first reach_real_target += student_score.average_score.to_f * target.weight.to_f if student_score end @@ -60,8 +60,19 @@ class Ecs::QueryCourseEvaluationService < ApplicationService def score_levels_map @_score_levels_map ||= begin + index = 0 ec_course.ec_score_levels.each_with_object({}) do |level, obj| - obj[level.id.to_s] = level.as_json(only: %i[id position score level]) + hash = level.as_json(only: %i[id position score level]) + + hash[:description] = + case index + when 0 then "#{level.score}分以上" + when ec_course.ec_score_levels.to_a.size - 1 then "低于#{level.score}分" + else "#{level.score}~#{ec_course.ec_score_levels[index - 1].score - 1}分" + end + + index += 1 + obj[level.id.to_s] = hash end end end @@ -87,23 +98,29 @@ class Ecs::QueryCourseEvaluationService < ApplicationService @_course_achievement += data[:average_score].to_f * course_target.weight.to_f # 计算学生成绩分布区间 + student_count = 0 data[:score_levels] = score_levels.map do |score_level| level_condition_proc = if (score_level.position - 1).zero? # 第一区间 -> (score_target){ score_target.score >= score_level.score ? 1 : 0 } - elsif score_levels.position == score_levels.size # 末尾区间 + elsif score_level.position == score_levels.size # 末尾区间 -> (score_target){ score_target.score < score_level.score ? 1 : 0 } else # 中间区间 - -> (score_target){ score_target.score >= score_level.score && score_target.score < score_targets[score_level.position - 1] ? 1 : 0 } + -> (score_target){ score_target.score >= score_level.score && score_target.score < score_levels[score_level.position - 1].score ? 1 : 0 } end # 计算该成绩区间人数 count = score_targets.sum(&level_condition_proc) + student_count += count { id: score_level.id, count: count } end + data[:score_levels].each do |score_level| + score_level[:rate] = score_level[:count].fdiv(student_count).round(2) + end + data end end