Commit 2c634bc6 by zhangleyuan

feat:处理任务排序

parent b3ffb2aa
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-21 16:08:38 * @Date: 2021-02-21 16:08:38
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-05 14:04:52 * @LastEditTime: 2021-03-09 12:54:31
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -43,4 +43,7 @@ export function removePlanCustomer(params: object) { ...@@ -43,4 +43,7 @@ export function removePlanCustomer(params: object) {
} }
export function getStorePlanAll(params: object) { export function getStorePlanAll(params: object) {
return Service.Hades("public/hades/getStorePlanAll", params); return Service.Hades("public/hades/getStorePlanAll", params);
}
export function getTrainingCourseAutoCancel(params: object) {
return Service.Hades("public/hades/getTrainingCourseAutoCancel", params);
} }
\ No newline at end of file
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: wufan * @Author: wufan
* @Date: 2020-11-25 18:25:02 * @Date: 2020-11-25 18:25:02
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-08 11:47:58 * @LastEditTime: 2021-03-09 10:28:03
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -73,4 +73,6 @@ export function updateStoreMessage(params: object) { ...@@ -73,4 +73,6 @@ export function updateStoreMessage(params: object) {
} }
export function getStoreDetail(params: object) { export function getStoreDetail(params: object) {
return Service.Hades("public/hades/getStoreDetail", params); return Service.Hades("public/hades/getStoreDetail", params);
} }
\ No newline at end of file
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-21 16:15:38 * @Date: 2021-02-21 16:15:38
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2021-03-05 14:04:25 * @LastEditTime: 2021-03-09 12:54:46
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import {getTrainingPlanPage,createTrainingPlan,updateStateTrainingPlan,getTrainingPlanDetail,updateTrainingPlan,deleteTrainingPlan,getPlanUserRecordPage,getPlanCustomerRecordPage,getPlanCustomerDetail,getPlanCustomerAboutUser,removePlanCustomer,getStorePlanAll} from '@/data-source/plan/request-apis'; import {getTrainingPlanPage,createTrainingPlan,updateStateTrainingPlan,getTrainingPlanDetail,updateTrainingPlan,deleteTrainingPlan,getPlanUserRecordPage,getPlanCustomerRecordPage,getPlanCustomerDetail,getPlanCustomerAboutUser,removePlanCustomer,getStorePlanAll,getTrainingCourseAutoCancel} from '@/data-source/plan/request-apis';
export default class PlanService { export default class PlanService {
// 获取员工列表 // 获取员工列表
static getTrainingPlanPage(params: any) { static getTrainingPlanPage(params: any) {
...@@ -45,4 +45,7 @@ export default class PlanService { ...@@ -45,4 +45,7 @@ export default class PlanService {
static getStorePlanAll(params: any) { static getStorePlanAll(params: any) {
return getStorePlanAll(params); return getStorePlanAll(params);
} }
static getTrainingCourseAutoCancel(params: any) {
return getTrainingCourseAutoCancel(params);
}
} }
\ No newline at end of file
...@@ -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-03-08 18:19:14 * @LastEditTime: 2021-03-09 12:54:53
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -27,7 +27,8 @@ const defaultBasicData = { ...@@ -27,7 +27,8 @@ const defaultBasicData = {
instro:'', instro:'',
operateType:'All_Operate', operateType:'All_Operate',
percentCompleteLive:80, percentCompleteLive:80,
percentCompleteVideo:80 percentCompleteVideo:80,
} }
const defaultTaskList = []; const defaultTaskList = [];
...@@ -36,12 +37,22 @@ function AddPlan() { ...@@ -36,12 +37,22 @@ function AddPlan() {
const type = getParameterByName("type"); const type = getParameterByName("type");
const [basicData,setBasicData] = useState(defaultBasicData); const [basicData,setBasicData] = useState(defaultBasicData);
const [taskList,setTaskList] = useState(defaultTaskList); const [taskList,setTaskList] = useState(defaultTaskList);
const [expiredCourseList,setExpiredCourseList] = useState([]);
useEffect(()=>{ useEffect(()=>{
if(type==='edit'){ if(type==='edit'){
getPlanDetail(); getPlanDetail();
getPlanCustomerState();
} }
},id) },id)
function getPlanDetail (){ function getPlanCustomerState(){
PlanService.getTrainingCourseAutoCancel({
planId: id
}).then((res) => {
const expiredCourseList = res.result;
setExpiredCourseList(expiredCourseList)
})
}
function getPlanDetail (){
PlanService.getTrainingPlanDetail({ PlanService.getTrainingPlanDetail({
planId: id planId: id
}).then((res) => { }).then((res) => {
...@@ -220,10 +231,10 @@ function AddPlan() { ...@@ -220,10 +231,10 @@ function AddPlan() {
<TrainingTask data={taskList} onChange={handleChangeTaskInfo} /> <TrainingTask data={taskList} onChange={handleChangeTaskInfo} />
} }
</div> </div>
{ type==='edit' && { (type==='edit' && expiredCourseList.length > 0) &&
<div className="expired-info__wrap"> <div className="expired-info__wrap">
<div className="title">失效课程</div> <div className="title">失效课程</div>
<ExpiredCourseList /> <ExpiredCourseList expiredCourseList={expiredCourseList}/>
</div> </div>
} }
</div> </div>
......
...@@ -4,33 +4,43 @@ import { withRouter } from 'react-router-dom'; ...@@ -4,33 +4,43 @@ import { withRouter } from 'react-router-dom';
import User from '@/common/js/user'; import User from '@/common/js/user';
import './ExpiredCourseList.less'; import './ExpiredCourseList.less';
function ExpiredCourseList() { function ExpiredCourseList(props) {
return ( return (
<div className="expired-course-list"> <div className="expired-course-list">
<div className="course-item"> { props.expiredCourseList.map((item,index)=>{
<div className="course-left"> return <div className="course-item">
<div className="course-status"> <div className="course-left">
未成功开课 <div className="course-status">
</div> 未成功开课
<div className="course-info">
<div className="course-type">
<span>直播课</span>
</div>
<div className="course-instro">
<div className="course-name">
课程名称最多四十个字课程名称最多四十个字课程名称最多四十个字课程名称最多四十个字
</div> </div>
<div className="task-name"> <div className="course-info">
培训名称最多二十个字培训名称最多二十个字 <div className="course-type">
{ item.courseType === "LIVE" &&
<span>直播课</span>
}
{ item.courseType === "VOICE " &&
<span>视频课</span>
}
</div>
<div className="course-instro">
<div className="course-name">
{item.courseName}
</div>
<div className="task-name">
{item.taskName}
</div>
</div>
</div> </div>
</div> </div>
<div className="course-time">
上课时间:{formatDate('YYYY-MM-DD H:i', item.startTime)}
</div>
</div> </div>
</div> })
<div className="course-time">
上课时间:47238095327 }
</div>
</div>
</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-03-09 10:04:40 * @LastEditTime: 2021-03-09 13:42:05
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -15,39 +15,42 @@ import RelatedCourseModal from '../modal/relatedCourseModal' ...@@ -15,39 +15,42 @@ import RelatedCourseModal from '../modal/relatedCourseModal'
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import './TrainingTask.less'; import './TrainingTask.less';
const { Panel } = Collapse const { Panel } = Collapse
const CourseType = {
LIVE: {
text: "直播课"
},
VOICE : {
text:"视频课"
},
RECORD : {
text:'录播课'
}
};
const courseStateShow = {
UN_START: {
title: "待开课",
},
STARTING: {
title: "上课中",
},
FINISH: {
title: "已完成",
},
EXPIRED: {
title: "未成功开课",
},
};
const DragHandle = sortableHandle(() => ( const DragHandle = sortableHandle(() => (
<span style={{ cursor: 'pointer', color: '#999' }} > <span className="operate__item" >
<span className="icon iconfont">&#xe7cd;</span> <span className="icon iconfont">&#xe7cd;</span>
<span>移动</span> <span className="text">移动</span>
</span> </span>
)); ));
const SortableItem = sortableElement(props => <tr {...props}/>); const SortableItem = sortableElement(props => <tr {...props}/>);
const SortableContainer = sortableContainer(props => <tbody {...props} />); const SortableContainer = sortableContainer(props => <tbody {...props} />);
const taskData = [
{
key: '1',
name: 'John Brown',
age: 32,
address: 'New York No. 1 Lake Park',
index: 0,
},
{
key: '2',
name: 'Jim Green',
age: 42,
address: 'London No. 1 Lake Park',
index: 1,
},
{
key: '3',
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
index: 2,
},
];
const SortableTaskItem = sortableElement(props => <div {...props}>{props.taskItem}</div>) const SortableTaskItem = sortableElement(props => <div {...props}>{props.taskItem}</div>)
const SortableTaskContainer = sortableContainer(props => <div {...props}></div>); const SortableTaskContainer = sortableContainer(props => <div {...props}></div>);
...@@ -209,8 +212,9 @@ class TrainingTask extends React.Component { ...@@ -209,8 +212,9 @@ class TrainingTask extends React.Component {
if (oldIndex !== newIndex) { if (oldIndex !== newIndex) {
const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter(el => !!el); const newData = arrayMove([].concat(dataSource), oldIndex, newIndex).filter(el => !!el);
console.log("newData",newData) this.setState({
this.setState({ dataSource: newData }); dataSource:newData,
},()=>{this.props.onChange(newData);})
} }
}; };
onCourseSortEnd = ({ oldIndex, newIndex },parentIndex) => { onCourseSortEnd = ({ oldIndex, newIndex },parentIndex) => {
...@@ -223,7 +227,9 @@ class TrainingTask extends React.Component { ...@@ -223,7 +227,9 @@ class TrainingTask extends React.Component {
const _dataSource = [...dataSource]; const _dataSource = [...dataSource];
if (oldIndex !== newIndex) { if (oldIndex !== newIndex) {
_dataSource[parentIndex].courseList = arrayMove([].concat(dataSource[parentIndex].courseList), oldIndex, newIndex).filter(el => !!el); _dataSource[parentIndex].courseList = arrayMove([].concat(dataSource[parentIndex].courseList), oldIndex, newIndex).filter(el => !!el);
this.setState({ dataSource:_dataSource }); this.setState({
dataSource:_dataSource,
},()=>{this.props.onChange(_dataSource);})
} }
}; };
...@@ -344,51 +350,116 @@ class TrainingTask extends React.Component { ...@@ -344,51 +350,116 @@ class TrainingTask extends React.Component {
this.props.onChange(newData); this.props.onChange(newData);
}) })
} }
openOrCloseTask = (index)=>{
renderTaskItem = (record,index)=>{ const {dataSource}= this.state;
return <div> const newData=[...dataSource];
newData[index].open = !newData[index].open;
<span> this.setState({
<span></span> dataSource:newData,
</span> },()=>{this.props.onChange(newData);})
{record.type==='input'?
<Form>
<Form.Item
validateTrigger={['onChange', 'onBlur']}
name={['taskName']}
rules={[
{
required: true,
message: "请输入任务名称",
},
]}>
<Input defaultValue={record.taskName} style={{ width: 300 }} placeholder="请输入任务名称(20字以内)" maxLength={20} onChange={(e) => { this.handleRenameTaskName(e,record)}} onBlur={(e)=>{this.handleTaskNameBlur(e,record)}}/>
</Form.Item>
</Form>
:
<span>{record.taskName}</span>
}
<DragHandle />
<div>
<SortableCourseContainer
useDragHandle
disableAutoscroll
helperClass="row-dragging"
onSortEnd={(record)=>this.onCourseSortEnd(record,index)} >
{record.courseList.map((courseItem, courseIndex) =>
<SortableCourseItem courseItem={this.renderCourseItem(courseItem,courseIndex)} index={courseIndex}>
</SortableCourseItem>
)}
</SortableCourseContainer>
<div><Button onClick={()=>{this.showRelatedCourseModal(index)}}><span>+</span><span>关联课程</span></Button></div>
</div>
</div>
} }
renderCourseItem = (record,index)=>{ renderTaskItem = (record,index)=>{
return <div> return <div className="task-item">
{record.courseName} <div className="task-con">
<DragHandle /> <div className="task-instro">
<span onClick={()=>this.openOrCloseTask(index)}>
{record.open?
<span className="icon iconfont open-icon">&#xe82d;</span>:
<span className="icon iconfont open-icon">&#xe835;</span>
}
</span>
{record.type==='input'?
<div className="task-name-con">
<span className="number">{index + 1}.</span>
<Form>
<Form.Item
validateTrigger={['onChange', 'onBlur']}
name={['taskName']}
rules={[
{
required: true,
message: "请输入任务名称",
},
]}>
<Input className="task-name-input" defaultValue={record.taskName} style={{ width: 300 }} placeholder="请输入任务名称(20字以内)" maxLength={20} onChange={(e) => { this.handleRenameTaskName(e,record)}} onBlur={(e)=>{this.handleTaskNameBlur(e,record)}}/>
</Form.Item>
</Form>
</div>
:
<div className="task-name-con">
<span className="number">{index + 1}.</span>
<span className="task-name">{record.taskName}</span>
</div>
}
</div>
<div className="operate">
<DragHandle />
<span className="operate__item">
<span className="icon iconfont">&#xe6f5;</span>
<span className="text" onClick={()=>{const { dataSource }= this.state; record.type="input";this.setState({dataSource})}}>重命名</span>
</span>
<span className="operate__item" onClick={()=>{this.handleDeleteTask(index)}} >
<span className="icon iconfont">&#xe6f6;</span>
<span className="text">删除</span>
</span>
</div>
</div>
{record.open &&
<div className="course-box">
<SortableCourseContainer
useDragHandle
disableAutoscroll
helperClass="row-dragging"
onSortEnd={(record)=>this.onCourseSortEnd(record,index)} >
{record.courseList.map((courseItem, courseIndex) =>
<SortableCourseItem courseItem={this.renderCourseItem(courseItem,courseIndex,index)} index={courseIndex}>
</SortableCourseItem>
)}
</SortableCourseContainer>
<div className="add-course-con"><span className="add-course-item" onClick={()=>{this.showRelatedCourseModal(index)}}><span>+</span><span>关联课程</span></span></div>
</div>
}
</div>
}
renderCourseItem = (record,index,parentIndex)=>{
return <div className="course-item">
<div className="course-info">
<span className="course-type">{CourseType[record.courseType].text}</span>
{record.type==='input'?
<Form>
<Form.Item
validateTrigger={['onChange', 'onBlur']}
name={['courseName']}
rules={[
{
required: true,
message: "请输入课程名称",
},
]}>
<Input className="course-name-input" defaultValue={record.courseName} style={{ width: 300 }} placeholder="请输入任务名称(40字以内)" maxLength={40} onChange={(e) => { this.handleRenameCourseName(e,record)}} onBlur={(e)=>{this.handleCourseNameBlur(e,record)}}/></Form.Item>
</Form>
:
<span className="course-name">{parentIndex + 1}.{index + 1}{record.courseName}</span>
}
{record.courseState === "EXPIRED" &&
<span className="icon iconfont tip">&#xe834;</span>
}
{ record.courseState &&
<span className="course-state">{courseStateShow[record.courseState].title}</span>
}
</div>
<div className="operate">
<DragHandle />
<span className="operate__item">
<span className="icon iconfont">&#xe6f5;</span>
<span className="text" onClick={(e)=>{const { dataSource } = this.state; record.type="input";this.setState({dataSource})}}>重命名</span>
</span>
<span className="operate__item" onClick={()=>{this.handleDeleteCourse(parentIndex,index)}}>
<span className="icon iconfont">&#xe6f6;</span>
<span className="text">删除</span>
</span>
</div>
</div> </div>
} }
render() { render() {
...@@ -397,7 +468,7 @@ class TrainingTask extends React.Component { ...@@ -397,7 +468,7 @@ class TrainingTask extends React.Component {
const { data } = this.props; const { data } = this.props;
return ( return (
<div className="training-task"> <div className="training-task">
<Table {/* <Table
pagination={false} pagination={false}
dataSource={dataSource} dataSource={dataSource}
columns={this.parseTaskColumns()} columns={this.parseTaskColumns()}
...@@ -429,8 +500,9 @@ class TrainingTask extends React.Component { ...@@ -429,8 +500,9 @@ class TrainingTask extends React.Component {
row: this.DraggableBodyRow, row: this.DraggableBodyRow,
}, },
}} }}
/> /> */}
{/* <SortableTaskContainer
<SortableTaskContainer
useDragHandle useDragHandle
disableAutoscroll disableAutoscroll
helperClass="row-dragging" helperClass="row-dragging"
...@@ -440,9 +512,9 @@ class TrainingTask extends React.Component { ...@@ -440,9 +512,9 @@ class TrainingTask extends React.Component {
<SortableTaskItem taskItem={this.renderTaskItem(item,index)} index={index}> <SortableTaskItem taskItem={this.renderTaskItem(item,index)} index={index}>
</SortableTaskItem> </SortableTaskItem>
)} )}
</SortableTaskContainer> */} </SortableTaskContainer>
<div><Button onClick={()=>this.addTask()}><span>+</span><span>添加任务</span></Button></div> <div className="add-task-con"><span className="add-task-btn" onClick={()=>this.addTask()}><span>+</span><span>添加任务</span></span></div>
{ relatedCourseModalVisible && { relatedCourseModalVisible &&
<RelatedCourseModal <RelatedCourseModal
selectedTaskIndex={selectedTaskIndex} selectedTaskIndex={selectedTaskIndex}
......
...@@ -2,4 +2,110 @@ ...@@ -2,4 +2,110 @@
thead{ thead{
display:none; display:none;
} }
.ant-form-item{
margin-bottom:0 !important;
}
.task-item{
.task-con{
display:flex;
padding:16px;
background: #F7F8F9;
border-radius: 2px;
justify-content: space-between;
align-items: center;
.task-instro{
display:flex;
align-items: center;
.open-icon{
color:#999999;
font-size:10px;
}
.task-name-con{
display:flex;
align-items: center;
color:#333333;
font-size:14px;
.number{
margin-right:10px;
margin-left:10px;
}
.task-name-input{
width: 300px;
height: 32px;
background: #FFFFFF;
border-radius: 4px;
}
}
}
}
.operate{
.operate__item{
cursor:pointer;
margin-left:16px;
color:#666666;
font-size:14px;
.icon{
color:#999;
}
.text{
margin-left:8px;
}
}
}
.course-box{
.course-item{
display:flex;
padding:16px 16px 16px 51px;
justify-content: space-between;
align-items: center;
.course-info{
.ant-form{
display:inline-block;
}
.course-name-input{
margin-right:8px;
}
.course-type{
font-size:11px;
color:#666666;
padding:1px 8px;
border: 1px solid #999999;
margin-right:4px;
border-radius: 2px;
}
.course-name{
color:#666666;
font-size:14px;
margin-right:8px;
}
.tip{
font-size:14px;
color:#FF4F4F;
margin-right:2px;
}
.course-state{
color:#999;
font-size:14px;
}
}
}
.add-course-con{
padding:16px 51px;
color: #5289FA;
font-size:14px;
}
}
}
.add-task-con{
height: 52px;
background: #F7F8F9;
border-radius: 2px;
padding:16px;
margin-top:16px;
.add-task-btn{
color: #5289FA;
font-size:14px;
}
}
} }
...@@ -295,6 +295,7 @@ class SelectOperatorModal extends React.Component { ...@@ -295,6 +295,7 @@ class SelectOperatorModal extends React.Component {
_item.courseId = item.id; _item.courseId = item.id;
_item.courseType = "VOICE"; _item.courseType = "VOICE";
_item.courseName = item.courseName; _item.courseName = item.courseName;
return _item; return _item;
}) })
} }
...@@ -304,6 +305,7 @@ class SelectOperatorModal extends React.Component { ...@@ -304,6 +305,7 @@ class SelectOperatorModal extends React.Component {
_item.courseId = item.liveCourseId; _item.courseId = item.liveCourseId;
_item.courseType = "LIVE"; _item.courseType = "LIVE";
_item.courseName = item.courseName; _item.courseName = item.courseName;
_item.courseState = item.courseState;
return _item; return _item;
}) })
} }
......
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