ecs: graduation requirement page

dev_cs
p31729568 5 years ago
parent 0ed5b1d79f
commit 665c6329d1

@ -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

@ -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

@ -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

@ -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

@ -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

@ -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 (
<div>
@ -56,6 +239,135 @@ class GraduationRequirement extends React.Component {
<Divider/>
<div className="graduation-requirement-body">
<div className="graduation-requirement-items">
<div className="graduation-requirement-items-head">
<div className="no-column">指标点</div>
<div className="item-content-column">内容</div>
<div className="operation-column">
{
can_manager && !addState && (
<Tooltip title="添加">
<Icon type="plus-circle" className="edit-action" onClick={this.showNewReqContent} />
</Tooltip>
)
}
</div>
</div>
<div className="graduation-requirement-items-body">
{
graduationRequirements && graduationRequirements.map((item, index) => {
return can_manager && index === editIndex ? (
<div className="graduation-requirement-items-body-item active" key={index}>
<div className="item-row item-head">
<div className="no-column">{ index + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!currentEditReq.content || currentEditReq.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={currentEditReq.content} onChange={this.onEditContentChange} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.addEditItem}/></Tooltip>
</div>
</div>
{
currentEditReq.ec_graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ index + 1 }-{ i + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!subitem.content || subitem.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={subitem.content} onChange={(e) => this.onEditItemContentChange(e, i)} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.removeEditItem(i)}/></Tooltip>
</div>
</div>
)
})
}
<div className="edit-form">
<Button type="primary" loading={submitState} onClick={this.saveContentEdit}>保存</Button>
<Button disabled={submitState} onClick={this.cancelContentEdit}>取消</Button>
</div>
</div>
) : (
<div className="graduation-requirement-items-body-item" key={index}>
<div className="item-row item-head">
<div className="no-column">{ index + 1 }</div>
<div className="item-content-column">{ item.content }</div>
{
can_manager && (
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.showDeleteConfirm(item.id)} /></Tooltip>
<Tooltip title="编辑"><Icon type="edit" theme="filled" className="edit-action" onClick={() => this.showEditContent(index)}/></Tooltip>
{
index === graduationRequirements.length - 1 && !addState && (
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.showNewReqContent}/></Tooltip>
)
}
</div>
)
}
</div>
{
item.ec_graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ index + 1 }-{ i + 1 }</div>
<div className="item-content-column">{ subitem.content }</div>
</div>
)
})
}
</div>
)
})
}
{
can_manager && addState && (
<div className="graduation-requirement-items-body-item active">
<div className="item-row item-head">
<div className="no-column">{ graduationRequirements.length + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!newRequirement.content || newRequirement.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={newRequirement.content} onChange={this.onNewReqContentChange} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="添加"><Icon type="plus-circle" style={{ color: '#29BD8B' }} onClick={this.addNewReqItem}/></Tooltip>
</div>
</div>
{
newRequirement.graduation_subitems.map((subitem, i) => {
return (
<div className="item-row" key={i}>
<div className="no-column">{ graduationRequirements.length + 1 }-{ i + 1 }</div>
<div className="item-content-column">
<Form.Item label={false} validateStatus={validateState && (!subitem.content || subitem.content.length === 0) ? 'error' : ''}>
<Input.TextArea rows={2} value={subitem.content} onChange={(e) => this.onNewReqItemContentChange(e, i)} />
</Form.Item>
</div>
<div className="item-column-operation">
<Tooltip title="删除"><Icon type="delete" onClick={() => this.removeNewReqItem(i)}/></Tooltip>
</div>
</div>
)
})
}
<div className="edit-form">
<Button type="primary" loading={submitState} onClick={this.saveNewReq}>保存</Button>
<Button disabled={submitState} onClick={this.cancelNewReq}>取消</Button>
</div>
</div>
)
}
</div>
</div>
</div>
</div>
</Spin>

@ -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;
}
}

@ -198,7 +198,7 @@ class TrainingObjective extends React.Component {
<div className="item-content-column">目标分解详情</div>
<div className="operation-column">
{
itemsEditState || (
!can_manager || itemsEditState || (
<Tooltip title="编辑">
<Icon type="edit" theme="filled" className="edit-action" onClick={this.editItemsContent} />
</Tooltip>

@ -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 {
<Switch>
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/training_objectives'
render={ (props) => (<TrainingObjective {...this.props} {...props} {...this.state} />) }></Route>
<Route extra path='/ecs/major_schools/:majorId/years/:yearId/graduation_requirement'
render={ (props) => (<GraduationRequirement {...this.props} {...props} {...this.state} />) }></Route>
</Switch>
)
}

Loading…
Cancel
Save