Commit da09f281 by zhangleyuan

feat:处理培训计划

parent b033a851
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:13:39 * @Date: 2021-02-20 16:13:39
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-02-22 16:45:21 * @LastEditTime: 2021-02-25 17:49:09
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -14,7 +14,29 @@ import BasicInfo from './components/BasicInfo'; ...@@ -14,7 +14,29 @@ import BasicInfo from './components/BasicInfo';
import TrainingTask from './components/TrainingTask' import TrainingTask from './components/TrainingTask'
import './AddPlan.less' import './AddPlan.less'
const DEFAULT_BASIC_DATA = {
planName:"",
enableState:"YES",
selectOperatorList:[],
instro:'',
operateType:'All_Operate',
percentCompleteLive:80,
percentCompleteVideo:80
}
function AddPlan() { function AddPlan() {
const [basicData,setBasicData] = useState(DEFAULT_BASIC_DATA);
function handleChangeBasicInfo(field, value){
console.log('field',value);
setBasicData( {
...basicData,
[field]: value,
}
)
}
return ( return (
<div className="page add-plan-page"> <div className="page add-plan-page">
<Breadcrumbs <Breadcrumbs
...@@ -27,7 +49,10 @@ function AddPlan() { ...@@ -27,7 +49,10 @@ function AddPlan() {
<div className="add-plan-page__form"> <div className="add-plan-page__form">
<div className="basic-info__wrap"> <div className="basic-info__wrap">
<div className="title">基本信息</div> <div className="title">基本信息</div>
<BasicInfo/> <BasicInfo
data={basicData}
onChange={handleChangeBasicInfo}
/>
</div> </div>
<div className="basic-info__wrap"> <div className="basic-info__wrap">
<div className="title">培训任务</div> <div className="title">培训任务</div>
......
...@@ -2,25 +2,51 @@ ...@@ -2,25 +2,51 @@
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-02-22 18:21:13 * @LastEditTime: 2021-02-25 17:48:12
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React, { useState, useRef, useEffect } from 'react';
import { Button,Input,Switch,Radio,Row,Col} from 'antd'; import { Button,Input,Switch,Radio,Row,Col} from 'antd';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import SelectOperatorModal from '../modal/SelectOperatorModal'
import './BasicInfo.less'; import './BasicInfo.less';
const { TextArea } = Input; const { TextArea } = Input;
function BasicInfo() { function BasicInfo(props) {
const [operatorModalVisible,setOperatorModalVisible] = useState(false);
function handleShowSelectOperatorModal(){
setOperatorModalVisible(true);
}
function handleCloseSelectOperatorMOdal(){
setOperatorModalVisible(false);
}
function handleConfirmSelectOperator(selectOperatorList){
console.log("selectOperatorList",selectOperatorList);
props.onChange('selectOperatorList',selectOperatorList);
setOperatorModalVisible(false);
}
function enableStateChange(){
if(props.data.enableState==="NO"){
props.onChange('enableState','YES')
}else{
props.onChange('enableState','NO')
}
}
return ( return (
<div className="plan-basic-info"> <div className="plan-basic-info">
<div className="plan-name"> <div className="plan-name">
<span className="label"><span className="require">*</span>课程名称:</span> <span className="label"><span className="require">*</span>课程名称:</span>
<Input <Input
value={props.data.planName}
placeholder="请输入培训计划名称,最多20字" placeholder="请输入培训计划名称,最多20字"
maxLength={20} maxLength={20}
style={{ width: 240 }} style={{ width: 240 }}
onChange={(e)=>props.onChange('planName', e.target.value)}
/> />
</div> </div>
<div className="cover"> <div className="cover">
...@@ -46,13 +72,15 @@ function BasicInfo() { ...@@ -46,13 +72,15 @@ function BasicInfo() {
maxLength={200} maxLength={200}
style={{ width: 480 }} style={{ width: 480 }}
className="instro-textarea" className="instro-textarea"
value={props.data.instro}
onChange={(e)=>props.onChange('instro', e.target.value)}
/> />
</div> </div>
<div className="wether-use"> <div className="wether-use">
<span className="label">是否启用:</span> <span className="label">是否启用:</span>
<div className="content"> <div className="content">
<div> <div>
<Switch checked={true} /> <Switch checked={props.data.enableState==="YES"? true:false} onChange={enableStateChange}/>
</div> </div>
<div> <div>
<div className="instro-text"> <div className="instro-text">
...@@ -65,10 +93,10 @@ function BasicInfo() { ...@@ -65,10 +93,10 @@ function BasicInfo() {
<div className="view-range" > <div className="view-range" >
<span className="label"><span className="require">*</span>可见范围:</span> <span className="label"><span className="require">*</span>可见范围:</span>
<div className="content"> <div className="content">
<Radio.Group > <Radio.Group value={props.data.operateType} onChange={(e) => { props.onChange('operateType', e.target.value) }}>
<Row style={{ marginBottom: '5px' }}> <Row style={{ marginBottom: '5px' }}>
<Col span={24}> <Col span={24}>
<Radio value="YES"> <Radio value="All_Operate">
所有运营师 所有运营师
<span className="playback__text">后续新增的运营师都有权限可见</span> <span className="playback__text">后续新增的运营师都有权限可见</span>
</Radio> </Radio>
...@@ -76,7 +104,7 @@ function BasicInfo() { ...@@ -76,7 +104,7 @@ function BasicInfo() {
</Row> </Row>
<Row> <Row>
<Col span={8}> <Col span={8}>
<Radio value="NO"> <Radio value="Assign_Operate ">
指定运营师 指定运营师
<span className="playback__text">仅被选择的运营师有权限可见</span> <span className="playback__text">仅被选择的运营师有权限可见</span>
</Radio> </Radio>
...@@ -84,8 +112,8 @@ function BasicInfo() { ...@@ -84,8 +112,8 @@ function BasicInfo() {
</Row> </Row>
</Radio.Group> </Radio.Group>
<div className="choose-business"> <div className="choose-business">
<Button>选择运营师</Button> <Button onClick={handleShowSelectOperatorModal}>选择运营师</Button>
<span>已选择<span>0</span>名运营师</span> <span>已选择<span>{props.data.selectOperatorList.length}</span>名运营师</span>
</div> </div>
</div> </div>
</div> </div>
...@@ -94,14 +122,22 @@ function BasicInfo() { ...@@ -94,14 +122,22 @@ function BasicInfo() {
<div> <div>
<div> <div>
<span className="icon iconfont">&#xe865;</span> <span className="icon iconfont">&#xe865;</span>
<span>直播课单个课程,用户学习进度达到<Input width="40"/>% 即视为“已完成”学习</span> <span>直播课单个课程,用户学习进度达到<Input width="40" value={props.data.percentCompleteLive} onChange={(e) => { props.onChange('percentCompleteLive', e.target.value) }}/>% 即视为“已完成”学习</span>
</div> </div>
<div> <div>
<span className="icon iconfont">&#xe864;</span> <span className="icon iconfont">&#xe864;</span>
<span>视频课单个课程,用户学习进度达到<Input width="40"/>%即视为“已完成”学习</span> <span>视频课单个课程,用户学习进度达到<Input width="40" value={props.data.percentCompleteVideo} onChange={(e) => { props.onChange('percentCompleteVideo', e.target.value) }} />%即视为“已完成”学习</span>
</div> </div>
</div> </div>
</div> </div>
{ operatorModalVisible &&
<SelectOperatorModal
visible={operatorModalVisible}
onClose={handleCloseSelectOperatorMOdal}
selectOperatorList={props.data.selectOperatorList}
onSelect={handleConfirmSelectOperator}
/>
}
</div> </div>
); );
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-02-24 19:53:39 * @LastEditTime: 2021-02-25 13:42:07
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -22,57 +22,63 @@ const DragHandle = sortableHandle(() => ( ...@@ -22,57 +22,63 @@ const DragHandle = sortableHandle(() => (
)); ));
const data = [ const data = [
{ // {
taskName: '培训计划名称A', // taskName: '培训计划名称A',
index:0, // index:0,
type:'text', // type:'text',
courserList:[ // courserList:[
{ // {
courseName:'培训计划课程A-1', // courseName:'培训计划课程A-1',
type:'text', // type:'text',
index:0 // index:0,
}, // id:'00'
{ // },
courseName:'培训计划课程A-2', // {
type:'text', // courseName:'培训计划课程A-2',
index:1 // type:'text',
}, // index:1,
{ // id:'01'
courseName:'培训计划课程A-3', // },
type:'text', // {
index:2 // courseName:'培训计划课程A-3',
} // type:'text',
] // index:2,
}, // id:'02'
{ // }
taskName: '培训计划名称B', // ]
index:1, // },
type:'text', // {
courserList:[ // taskName: '培训计划名称B',
{ // index:1,
courseName:'培训计划课程B-1', // type:'text',
index:0, // courserList:[
type:'text', // {
}, // courseName:'培训计划课程B-1',
{ // index:0,
courseName:'培训计划课程B-2', // type:'text',
index:1, // id:'10'
type:'text', // },
} // {
] // courseName:'培训计划课程B-2',
}, // index:1,
{ // type:'text',
taskName: '培训计划名称C', // id:'11'
index:2, // }
type:'text', // ]
courserList:[ // },
{ // {
courseName:'培训计划课程c-1', // taskName: '培训计划名称C',
index:0, // index:2,
type:'text' // type:'text',
} // courserList:[
] // {
}, // courseName:'培训计划课程c-1',
// index:0,
// type:'text',
// id:'20'
// }
// ]
// },
]; ];
const SortableItem = sortableElement(props => <tr {...props} />); const SortableItem = sortableElement(props => <tr {...props} />);
...@@ -92,7 +98,7 @@ class TrainingTask extends React.Component { ...@@ -92,7 +98,7 @@ class TrainingTask extends React.Component {
title: 'taskName', title: 'taskName',
dataIndex: 'taskName', dataIndex: 'taskName',
className: 'drag-visible', className: 'drag-visible',
render: (val, record) => { render: (val, record,index) => {
return ( return (
<div> <div>
{record.type==='text'? {record.type==='text'?
...@@ -118,7 +124,7 @@ class TrainingTask extends React.Component { ...@@ -118,7 +124,7 @@ class TrainingTask extends React.Component {
key: 'operate', key: 'operate',
dataIndex: 'operate', dataIndex: 'operate',
width: '25%', width: '25%',
render: (val, record) => { render: (val, record,index) => {
return ( return (
<div className="operate"> <div className="operate">
<DragHandle /> <DragHandle />
...@@ -126,7 +132,7 @@ class TrainingTask extends React.Component { ...@@ -126,7 +132,7 @@ class TrainingTask extends React.Component {
<span className="icon iconfont">&#xe6f5;</span> <span className="icon iconfont">&#xe6f5;</span>
<span onClick={(e)=>{const {dataSource}= this.state; record.type="input";this.setState(dataSource)}}>重命名</span> <span onClick={(e)=>{const {dataSource}= this.state; record.type="input";this.setState(dataSource)}}>重命名</span>
</span> </span>
<span className="operate__item"> <span className="operate__item" onClick={()=>{this.handleDeleteTask(index)}} >
<span className="icon iconfont">&#xe6f6;</span> <span className="icon iconfont">&#xe6f6;</span>
<span>删除</span> <span>删除</span>
</span> </span>
...@@ -137,7 +143,7 @@ class TrainingTask extends React.Component { ...@@ -137,7 +143,7 @@ class TrainingTask extends React.Component {
]; ];
return columns; return columns;
} }
parseCoursecolumns = ()=>{ parseCoursecolumns = (parentIndex)=>{
const coursecolumns = [ const coursecolumns = [
{ {
title: 'courseName', title: 'courseName',
...@@ -170,7 +176,7 @@ class TrainingTask extends React.Component { ...@@ -170,7 +176,7 @@ class TrainingTask extends React.Component {
key: 'operate', key: 'operate',
dataIndex: 'operate', dataIndex: 'operate',
width: '25%', width: '25%',
render: (val, record) => { render: (val, record,index) => {
return ( return (
<div className="operate"> <div className="operate">
<DragHandle /> <DragHandle />
...@@ -178,7 +184,7 @@ class TrainingTask extends React.Component { ...@@ -178,7 +184,7 @@ class TrainingTask extends React.Component {
<span className="icon iconfont">&#xe6f5;</span> <span className="icon iconfont">&#xe6f5;</span>
<span onClick={(e)=>{const {dataSource}= this.state; record.type="input";this.setState(dataSource)}}>重命名</span> <span onClick={(e)=>{const {dataSource}= this.state; record.type="input";this.setState(dataSource)}}>重命名</span>
</span> </span>
<span className="operate__item"> <span className="operate__item" onClick={()=>{this.handleDeleteCourse(parentIndex,index)}}>
<span className="icon iconfont">&#xe6f6;</span> <span className="icon iconfont">&#xe6f6;</span>
<span>删除</span> <span>删除</span>
</span> </span>
...@@ -231,7 +237,6 @@ class TrainingTask extends React.Component { ...@@ -231,7 +237,6 @@ class TrainingTask extends React.Component {
handleRenameTaskName = (e,record) => { handleRenameTaskName = (e,record) => {
const { value } = e.target; const { value } = e.target;
const { index } = record;
const { dataSource } = this.state; const { dataSource } = this.state;
record.taskName = value; record.taskName = value;
} }
...@@ -246,7 +251,6 @@ class TrainingTask extends React.Component { ...@@ -246,7 +251,6 @@ class TrainingTask extends React.Component {
handleRenameCourseName = (e,record) => { handleRenameCourseName = (e,record) => {
const { value } = e.target; const { value } = e.target;
const { index } = record;
const { dataSource } = this.state; const { dataSource } = this.state;
record.courseName = value; record.courseName = value;
} }
...@@ -258,9 +262,21 @@ class TrainingTask extends React.Component { ...@@ -258,9 +262,21 @@ class TrainingTask extends React.Component {
record.type="text"; record.type="text";
this.setState(dataSource); this.setState(dataSource);
} }
} }
handleDeleteTask = (index)=>{
const {dataSource}= this.state;
const newData=[...dataSource];
newData.splice(index,1);
this.setState({dataSource:newData});
}
handleDeleteCourse = (parentIndex,index)=>{
const {dataSource}= this.state;
const newData=[...dataSource];
const selectData = [...newData[parentIndex].courserList]
selectData.splice(index,1)
newData[parentIndex].courserList= selectData;
this.setState({dataSource:newData});
}
render() { render() {
const { dataSource } = this.state; const { dataSource } = this.state;
...@@ -271,20 +287,20 @@ class TrainingTask extends React.Component { ...@@ -271,20 +287,20 @@ class TrainingTask extends React.Component {
dataSource={dataSource} dataSource={dataSource}
columns={this.parseTaskColumns()} columns={this.parseTaskColumns()}
rowKey="index" rowKey="index"
expandedRowRender={(record) => { expandedRowRender={(record,index) => {
if (record.courserList.length !== 0){ if (record.courserList.length !== 0){
return <div> return <div>
<Table <Table
pagination={false} pagination={false}
dataSource={record.courserList} dataSource={record.courserList}
columns={this.parseCoursecolumns()} columns={this.parseCoursecolumns(index)}
rowKey="index" rowKey="index"
components={{ // components={{
body: { // body: {
wrapper: this.DraggableContainer, // wrapper: this.DraggableContainer,
row: this.DraggableBodyRow, // row: this.DraggableBodyRow,
}, // },
}} // }}
/> />
<div><Button><span>+</span><span>关联课程</span></Button></div> <div><Button><span>+</span><span>关联课程</span></Button></div>
</div> </div>
......
import React from 'react';
import {Table, Modal,Input} from 'antd';
import { PageControl } from "@/components";
import StoreService from "@/domains/store-domain/storeService";
import User from '@/common/js/user'
import './SelectOperatorModal.less';
import _ from "underscore";
const { Search } = Input;
class SelectOperatorModal extends React.Component {
constructor(props) {
super(props);
this.state = {
dataSource:[],
size:10,
query: {
current: 1,
},
totalCount:0,
selectOperatorList:props.selectOperatorList
};
}
componentDidMount() {
this.handleFetchDataList();
}
// 获取运营师列表
handleFetchDataList = () => {
const {query,size,totalCount} = this.state
const params ={
...query,
size
}
StoreService.getStoreUserBasicPage(params).then((res) => {
const { result = {} } = res ;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total)
});
});
}
handleChangNickname = (value)=>{
const isPhone = (value || '').match(/^\d+$/);
const { query } = this.state;
if(isPhone){
query.phone = value;
query.nickName = null;
}else{
query.nickName = value;
query.phone = null;
}
query.current = 1;
this.setState({
query
})
}
onShowSizeChange = (current, size) => {
if (current == size) {
return
}
this.setState({
size
},()=>{this.handleFetchDataList()})
}
// 请求表头
parseColumns = () => {
const columns = [
{
title: '姓名',
key: 'nickName',
dataIndex: 'nickName'
},
{
title: '手机号',
key: 'phone',
dataIndex: 'phone'
}
];
return columns;
}
selectOperator = (record,selected) =>{
const {selectOperatorList} = this.state;
let _list = [];
if (selected || !_.find(selectOperatorList, (item) => item.id == record.id)) {
_list = _.uniq(selectOperatorList.concat([record]), false, (item) => item.id);
} else {
_list = _.reject(selectOperatorList, (item) => item.id === record.id);
}
this.setState({selectOperatorList:_list});
}
render() {
const { size,dataSource,totalCount,query,selectOperatorList} = this.state;
const { visible } = this.props;
return (
<Modal
title="选择运营师"
onCancel={this.props.onClose}
maskClosable={false}
visible={visible}
className="select-operator-modal"
closable={true}
width={800}
onOk={() => this.props.onSelect(selectOperatorList) }
>
<div className="search-container">
<Search placeholder="搜索运营师/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} />
</div>
<div>
<Table
rowKey={record => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
rowSelection={{
type: 'checkbox',
selectedRowKeys: _.pluck(selectOperatorList, 'id'),
onSelect: (record, selected) => {
this.selectOperator(record, selected)
},
onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = [];
if (selected) {
_list = _.uniq(selectOperatorList.concat(changeRows), false, (item) => item.id);
} else {
_list = _.reject(selectOperatorList, (item) => _.find(changeRows, (data) => data.id === item.id));
}
this.setState({selectOperatorList:_list});
},
}}
/>
{dataSource.length >0 &&
<div className="box-footer">
<PageControl
current={query.current - 1}
pageSize={size}
total={totalCount}
toPage={(page) => {
const _query = {...query, current: page + 1};
this.setState({
query:_query
},()=>{ this.handleFetchDataList()})
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
}
</div>
</Modal>
)
}
}
export default SelectOperatorModal;
\ No newline at end of file
.select-operator-modal{
.search-container{
margin-bottom:16px;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment