ec department index page

dev_cs
p31729568 5 years ago
parent 6f68c79f18
commit eabad1165a

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

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

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

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

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

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

@ -55,7 +55,13 @@ class Users::BaseController < ApplicationController
page = page_value
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

@ -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]}"

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

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

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

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

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

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

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

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

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

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

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

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

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

@ -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)=>(<Help {...this.props} {...props} {...this.state}></Help>)
}/>
<Route exact path="/ecs/department"
render={
(props)=>(<EcsHome {...this.props} {...props} {...this.state}></EcsHome>)
}/>
<Route exact path="/" component={ShixunsHome}/>
<Route component={Shixunnopage}/>

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

@ -0,0 +1,173 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Modal, Input, Table, message } from 'antd';
import axios from 'axios';
import './AddMajorModal.scss';
const { Search } = Input;
const tableColumns = [
{ title: '专业代码', dataIndex: 'code', key: 'code', width: 100, },
{ title: '专业名称', dataIndex: 'name', key: 'name', },
{ title: '', dataIndex: 'selected', key: 'selected', width: 80, render: selected => selected && <span className="color-orange">已选择</span> },
];
const defaultPagination = { current: 1, pageSize: 10, total: 0 };
class AddMajorModal extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
confirmLoading: false,
error: '',
keyword: '',
pagination: {...defaultPagination},
schoolId: props.schoolId,
majorData: [],
selectedData: []
}
this.getMajors = this.getMajors.bind(this);
this.selectMajor = this.selectMajor.bind(this);
this.onAfterModalClose = this.onAfterModalClose.bind(this);
this.handleOk = this.handleOk.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.onPaginationChange = this.onPaginationChange.bind(this);
}
componentDidUpdate(prevProps) {
if(!prevProps.visible && this.props.visible){
this.getMajors();
}
}
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 (
<div>
<Modal
title="添加认证专业"
wrapClassName="add-major-modal"
visible={this.props.visible}
confirmLoading={this.state.confirmLoading}
afterClose={this.onAfterModalClose}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div className="add-major-search">
<Search
placeholder="专业代码/专业名称检索"
onInput={e => this.setState({keyword: e.target.value})}
onSearch={this.getMajors}
value={keyword}/>
</div>
<div className="add-major-body">
<Table rowKey="id"
rowSelection={{onChange: this.selectMajor, getCheckboxProps: this.getCheckboxProps, selectedRowKeys: selectedData}}
loading={loading}
columns={tableColumns}
dataSource={majorData}
pagination={{...pagination, onChange: this.onPaginationChange}}
size="small"
scroll={{ y: 200 }}/>
<div className="error">{ this.state.error }</div>
</div>
</Modal>
</div>
)
}
}
AddMajorModal.propTypes = {
schoolId: PropTypes.number,
visible: PropTypes.bool,
onHide: PropTypes.func
}
export default AddMajorModal

@ -0,0 +1,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;
}
}

@ -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) => <div style={{ wordWrap: 'break-word', wordBreak: 'break-all' }}> {text} </div>
const tableColumns = [
{ title: '姓名', dataIndex: 'name', key: 'name', width: 60, render: columnRender },
{ title: '职称', dataIndex: 'identity', key: 'identity', width: 60, },
{ title: '单位', dataIndex: 'school_name', key: 'school_name', render: (_, record) => columnRender(`${record.school_name} ${record.department_name}`) },
{ title: '手机号', dataIndex: 'phone', key: 'phone', width: 80, },
];
const defaultPagination = { current: 1, pageSize: 20, total: 0 };
class AddManagerModal extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
confirmLoading: false,
nameValidateStatus: '',
error: '',
name: '',
school: props.schoolName,
identity: '',
pagination: {...defaultPagination},
schoolId: props.schoolId,
userData: [],
selectedData: []
}
this.getUsers = this.getUsers.bind(this);
this.selectUser = this.selectUser.bind(this);
this.onAfterModalClose = this.onAfterModalClose.bind(this);
this.handleOk = this.handleOk.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.onPaginationChange = this.onPaginationChange.bind(this);
}
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 (
<div>
<Modal
title="添加管理员"
wrapClassName="add-ec-manager-modal"
visible={this.props.visible}
confirmLoading={this.state.confirmLoading}
afterClose={this.onAfterModalClose}
onOk={this.handleOk}
onCancel={this.handleCancel}>
<div className="add-ec-manager-search">
<Form layout="horizontal">
<Row>
<Col span={12}>
<Form.Item label="姓名" labelCol={{ span: 6 }} wrapperCol={{span: 16}} validateStatus={nameValidateStatus}>
<Input onChange={this.onNameChange} value={name} placeholder="请输入姓名" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item label="职业" labelCol={{ span: 6 }} wrapperCol={{span: 17}} >
<Select value={identity} onChange={value => this.setState({ identity: value }) } placeholder="请选择职业">
<Option value="">全部</Option>
<Option value="teacher">教师</Option>
<Option value="student">学生</Option>
<Option value="professional">专业人士</Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row>
<Col span={18}>
<Form.Item label="学校" labelCol={{ span: 4 }} wrapperCol={{span: 18}}>
<Input onChange={e => this.setState({ school: e.target.value })} value={school} placeholder="请输入学校名称"/>
</Form.Item>
</Col>
<Col span={4} offset={2}>
<Button type="primary" className="mt5" onClick={this.getUsers}>搜索</Button>
</Col>
</Row>
</Form>
</div>
<div className="add-ec-manager-body">
<Table rowKey="id"
rowSelection={{onChange: this.selectUser, getCheckboxProps: this.getCheckboxProps, selectedRowKeys: selectedData, columnWidth: 40}}
loading={loading}
columns={tableColumns}
dataSource={userData}
pagination={{...pagination, onChange: this.onPaginationChange}}
size="small"
scroll={{ y: 200 }}/>
<div className="error">{ this.state.error }</div>
</div>
</Modal>
</div>
)
}
}
AddManagerModal.propTypes = {
schoolId: PropTypes.string,
schoolName: PropTypes.string,
majorId: PropTypes.number,
visible: PropTypes.bool,
onHide: PropTypes.func
}
export default AddManagerModal

@ -0,0 +1,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;
}
}

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

@ -0,0 +1,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 (
<div className="newMain clearfix">
<Spin spinning={this.state.loading} size="large" style={{marginTop:'15%'}}>
<div className="ec-home">
<div className="pr mb20">
<div className="head-image" style={{background: `url(${bgImage}) no-repeat top center`}}>
<span className="font-30 color-white font-bd">{ school && school.name }</span>
</div>
</div>
<div className="educontent mb20 ec-home-item school-manager-item">
<div className="ec-home-item-head">
<div className="ec-home-item-label">学校管理员</div>
<div className="ec-home-item-tip">温馨提醒学校管理员有添加专业及设置专业管理员等权限</div>
</div>
<div className="ec-home-item-body ec-school-manager">
{
managers && managers.map((manager) => {
return (
<Link to={`/users/${manager.login}`} key={manager.id} className="ec-school-manager-item">
<Avatar size={48} src={getImageUrl(`images/${manager.image_url}`)} alt="头像"/>
<Tooltip title={manager.name} placement="bottom">
<span className="ec-school-manager-name">{ manager.name }</span>
</Tooltip>
</Link>
)
})
}
</div>
</div>
<div className="educontent mb50 ec-home-item major-list-item">
<div className="ec-home-item-head">
<div className="major-list-item-head">
<div className="ec-home-item-label">专业列表</div>
<div className="ec-home-item-tip">
<span>请添加参与认证的专业名称</span>
<Link to="/forums/3527" target="_blank" className="link ml10">查看详情</Link>
</div>
</div>
<Button type="primary" onClick={() => { this.setState({ AddMajorVisible: true }) }}>添加专业</Button>
</div>
<Divider/>
<div className="major-list-container">
<div className="major-list-head">
<div className="total">{majorCount || 0} 个检索结果{majorCount || 0} 专业</div>
<Search
placeholder="专业代码/专业名称检索"
onInput={e => this.setState({searchKeyword: e.target.value})}
onSearch={this.getSchoolMajors}
value={this.state.searchKeyword}
style={{ width: 200 }}
/>
</div>
<div className="major-list-body">
<Row className="major-list-row head">
<Col span={2} className="textcenter">序号</Col>
<Col span={4}>专业代码</Col>
<Col span={6}>专业名称</Col>
<Col span={8}>专业管理员</Col>
<Col span={4} className="textcenter">操作</Col>
</Row>
<Spin spinning={this.state.majorLoading}>
{
templateMajor && (
<Row className="major-list-row">
<Col span={2} className="textcenter">0</Col>
<Col span={4}>000000</Col>
<Col span={6}>
<Link to={`/ecs/major_schools/${templateMajor.id}`}>{ templateMajor.name }</Link>
</Col>
<Col span={8}></Col>
<Col span={4} className="textcenter">
<a className="link">{ configBtnText }</a>
</Col>
</Row>
)
}
{
majors && majors.map((major, index) => {
return (
<Row className="major-list-row" key={major.id}>
<Col span={2} className="textcenter">{ index + 1 }</Col>
<Col span={4}>{ major.code }</Col>
<Col span={6}>
<Link to={`/ecs/major_schools/${major.id}`}>{ major.name }</Link>
</Col>
<Col span={8}>
<div className="manager-box">
{ manageMajor && <a className="link mr10" onClick={() => this.showAddManagerModal(major.id)}><Icon type="plus-circle" /></a> }
<MajorManager schoolId={school.id}
majorId={major.id}
canManage={manageMajor}
managers={major.major_managers}></MajorManager>
</div>
</Col>
<Col span={4} className="textcenter operate-box">
<a className="link">{ configBtnText }</a>
{ manageSchool && ( <a className="link" onClick={() => this.showDeleteMajorConfirm(major.id)}>删除</a> ) }
</Col>
</Row>
)
})
}
</Spin>
</div>
</div>
</div>
</div>
<AddMajorModal schoolId={this.state.schoolId} visible={this.state.AddMajorVisible} onHide={this.HideAddMajorModal}/>
{ this.state.school && <AddManagerModal schoolId={this.state.schoolId} schoolName={this.state.school.name} majorId={this.state.currentMajorId} visible={this.state.AddManagerVisible} onHide={this.HideAddManagerModal}/> }
</Spin>
</div>
)
}
}
export default SnackbarHOC() (TPMIndexHOC ( Home ));

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

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

Loading…
Cancel
Save