Commit 3ebe2c4f by yuananting

feat:培训任务列表接口联调

parent 246ca3f7
/*
* @Author: yuananting
* @Date: 2021-08-06 17:35:35
* @LastEditors: yuananting
* @LastEditTime: 2021-08-09 14:23:07
* @Description: 任务中心接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import Service from '@/common/js/service';
export function getTrainingTaskPage(params: object) {
return Service.Hades('public/hades/getTrainingTaskPage', params);
}
export function createTrainingExam(params: object) {
return Service.Hades('public/hades/createTrainingExam', params);
}
export function createTrainingTask(params: object) {
return Service.Hades('public/hades/createTrainingTask', params);
}
/*
* @Author: yuananting
* @Date: 2021-08-06 17:32:41
* @LastEditors: yuananting
* @LastEditTime: 2021-08-09 14:23:33
* @Description: 任务中心-培训任务接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import { getTrainingTaskPage, createTrainingExam, createTrainingTask } from '@/data-source/taskCenter/request-apis';
export default class TaskCenterService {
// 获取培训任务列表
static getTrainingTaskPage(params: any) {
return getTrainingTaskPage(params);
}
// 培训任务创建考试
static createTrainingExam(params: any) {
return createTrainingExam(params);
}
// 企培创建培训任务
static createTrainingTask(params: any) {
return createTrainingTask(params);
}
}
......@@ -2,40 +2,37 @@
* @Author: yuananting
* @Date: 2021-07-29 13:57:03
* @LastEditors: yuananting
* @LastEditTime: 2021-08-04 17:47:51
* @LastEditTime: 2021-08-09 17:39:56
* @Description: 任务中心-培训任务-新建页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useEffect, useState } from 'react';
import { Button, Tabs, message, Modal, Space } from 'antd';
import { Button, message, Modal, Space } from 'antd';
import ShowTips from '@/components/ShowTips';
import Breadcrumbs from '@/components/Breadcrumbs';
import BasicInfo from './components/BasicInfo';
import TrainContent from './components/TrainContent';
// import ExpiredCourseList from './components/ExpiredCourseList';
import PlanService from '@/domains/plan-domain/planService';
import User from '@/common/js/user';
import _ from 'underscore';
import './AddTrainTask.less';
import Bus from '@/core/bus';
const { TabPane } = Tabs;
import Upload from '@/core/upload';
import { randomString } from '@/domains/basic-domain/utils';
const defaultCover = 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png';
const DEFAULT_BASIC_INFO = {
taskName: '', // 培训任务名称
// createId: User.getStoreUserId(), // 创建人id
// storeId: User.getStoreId(), // 学院id
// issueState: 'YES', // 是否发布此计划(底部按钮区分)
// scheduleMediaRequests: [], // 封面图-(简介待定)
coverUrl: '',
taskName: '1', // 培训任务名称
coverUrl: defaultCover,
coverId: null,
trainingStageList: [], // 培训内容
helpStoreUserIds: [], // 指定协同者id
timeType: 'VALIDITY', // 培训时间,默认永久有效
timeType: 'FOREVER', // 培训时间,默认永久有效
startTime: null, // 固定时间段-开始时间
endTime: null, // 固定时间段-结束时间
learnType: 'FREEDOM', // 学习模式,默认自由学习
assignList: [], // 指派列表-assignId assignType
instro: null, // 培训目的
introduce: null, // 培训目的
};
const DEFAULT_STAGE_LIST = [
......@@ -60,9 +57,10 @@ function AddTrainTask() {
const [finishStandard, setFinishStandard] = useState(DEFAULT_FINISH_STANDARD); // 完成百分比
const [startCheck, setStartCheck] = useState(false); // 是否启动校验
useEffect(() => {
console.log('basicInfo:', basicInfo);
}, [basicInfo]);
// useEffect(() => {
// }, [basicInfo]);
console.log('basicInfo=====>', basicInfo);
function renderFooter() {
return (
......@@ -70,8 +68,8 @@ function AddTrainTask() {
<When condition={activeStep === 'BASIC_INFO'}>
<div className='footer shrink-footer'>
<Button onClick={handleGoBack}>取消</Button>
<Button onClick={handleSubmit}>保存</Button>
<Button type='primary' onClick={() => console.log('下一步')}>
<Button onClick={() => handleSubmit('NO')}>保存</Button>
<Button type='primary' onClick={() => setActiveStep('TRAIN_CONTENT')}>
下一步
</Button>
{/* disabled={submitDisabled} */}
......@@ -80,9 +78,9 @@ function AddTrainTask() {
<Otherwise>
<div className='footer shrink-footer'>
<Button onClick={handleGoBack}>取消</Button>
<Button onClick={() => console.log('上一步')}>上一步</Button>
<Button onClick={handleSubmit}>保存</Button>
<Button type='primary' onClick={() => console.log('提交')}>
<Button onClick={() => setActiveStep('BASIC_INFO')}>上一步</Button>
<Button onClick={() => handleSubmit('NO')}>保存</Button>
<Button type='primary' onClick={() => handleSubmit('YES')}>
保存并发布
</Button>
{/* disabled={submitDisabled} */}
......@@ -92,11 +90,61 @@ function AddTrainTask() {
);
}
function handleSubmit() {
function submitRemote(introduceId, issue) {
const { endTime, helpStoreUserIds, learnType, startTime, taskName, timeType, coverId, coverUrl } = basicInfo;
const { percentCompleteLive, percentCompletePicture, percentCompleteVideo } = finishStandard;
const commonParams = {
assignList: [
// 指派对象
{
assignId: '',
assignName: '',
assignType: '',
},
],
createId: User.getUserId(),
endTime,
helpStoreUserIds, // 协同者集合
issueState: issue, // 是否发布
learnType, // 学习模式
scheduleMediaRequests: [
{
contentType: 'COVER',
mediaContent: coverId,
mediaType: 'PICTURE',
mediaUrl: coverUrl,
},
],
startTime,
storeId: User.getStoreId(),
taskName,
timeType,
percentCompleteLive,
percentCompletePicture,
percentCompleteVideo,
introduceId,
};
console.log('commonParams:', commonParams);
}
function handleSubmit(issue) {
setStartCheck(true);
if (stageList.length === 0) {
return message.warning('请添加阶段');
}
Upload.uploadTextToOSS(
basicInfo.introduce,
`${randomString()}.txt`,
(introduceId) => {
submitRemote(introduceId, issue);
},
() => message.warning('上传培训目的失败')
);
}
function handleGoBack() {
......@@ -104,20 +152,34 @@ function AddTrainTask() {
}
function handleChangeBasicInfo(field, value) {
if (field === 'trainDate') {
console.log('handleChangeBasicInfo====>', basicInfo, field, value);
if (field === 'coverUrl') {
setBasicInfo({
...basicInfo,
coverUrl: value.fileUrl,
coverId: value.resourceId,
});
} else if (field === 'trainDate') {
// 固定培训时间,设置起始
setBasicInfo({
...basicInfo,
startTime: value && value[0]?.valueOf(),
endTime: value && value[1]?.valueOf(),
});
} else {
} else if (field === 'timeType' && value === 'FOREVER') {
setBasicInfo({
...basicInfo,
[field]: value,
startTime: null,
endTime: null,
});
} else {
let a = {
...basicInfo,
[field]: value,
};
console.log('a====>', a);
setBasicInfo(a);
}
}
......@@ -158,7 +220,7 @@ function AddTrainTask() {
</div>
{activeStep === 'BASIC_INFO' && <BasicInfo basicInfo={basicInfo} startCheck={startCheck} onChange={handleChangeBasicInfo} />}
{activeStep === 'TRAIN_CONTENT' && (
<TrainContent stageList={stageList} startCheck={startCheck} finishStandard={finishStandard} onChange={handleChangeStageInfo} />
<TrainContent stageList={stageList} basicInfo={basicInfo} startCheck={startCheck} finishStandard={finishStandard} onChange={handleChangeStageInfo} />
)}
</div>
{renderFooter()}
......
......@@ -2,37 +2,45 @@
* @Author: yuananting
* @Date: 2021-07-28 11:25:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-05 16:33:23
* @LastEditTime: 2021-08-09 11:41:40
* @Description: 任务中心-培训任务
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useEffect, useState } from 'react';
import TrainFilter from './components/TrainFilter';
import { Route, withRouter } from 'react-router-dom'
import { Route, withRouter } from 'react-router-dom';
import TrainList from './components/TrainList';
// import PlanList from './components/PlanList'
import PlanService from '@/domains/plan-domain/planService';
import TaskCenterService from '@/domains/task-center-domain/TaskCenterService';
import DataCenter from '../data-center/Index';
import User from '@/common/js/user';
function TrainTaskPage(props) {
const [trainListData, setTrainListData] = useState([]); // 培训任务列表
const [query, setQuery] = useState({
issueState: 'ALL', // 发布状态
myAssist: false, // 是否协同
current: 1,
endTime: null,
issueState: 'ALL', // 发布状态
myAssist: false, // 是否由我协同
size: 10,
sortMap: {}, // 排序
startTime: null,
storeId: User.getStoreId(),
storeUserId: User.getStoreUserId(),
taskName: '',
});
const [totalCount, setTotalCount] = useState(0); // 总数
const { match } = props;
useEffect(() => {
handleFetchTrainList();
getTrainingTaskPage();
}, [query]);
//动态获取计划列表
function handleFetchTrainList() {
PlanService.getTrainingPlanPage(query).then((res) => {
// 获取计划列表
function getTrainingTaskPage() {
let _query = _.clone(query);
if (_query.issueState === 'ALL') {
delete _query.issueState;
}
TaskCenterService.getTrainingTaskPage(_query).then((res) => {
const {
result: { records = [], total },
} = res;
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-29 14:32:24
* @LastEditors: yuananting
* @LastEditTime: 2021-08-06 13:59:25
* @LastEditTime: 2021-08-09 17:46:08
* @Description: 任务中心-培训任务-新建-基本信息
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -25,12 +25,10 @@ const FormItem = Form.Item;
function BasicInfo(props) {
const { basicInfo, startCheck } = props;
const { taskName, coverUrl, helpStoreUserIds, timeType, startTime, endTime, learnType, assignList, instro } = basicInfo;
const { taskName, coverUrl, helpStoreUserIds, timeType, startTime, endTime, learnType, assignList, introduce } = basicInfo;
const [imageFile, setImageFile] = useState(null); // 需要被截取的图片
const [showSelectFileModal, setShowSelectFileModal] = useState(false);
const [imgClipVisible, setImgClipVisible] = useState(false);
const [coverClicpPath, setCoverClicpPath] = useState(null);
const [coverId, setCoverId] = useState(null);
// 当前是否使用的是默认图片
const defaultCover = 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png';
const isDefaultCover = coverUrl === defaultCover;
......@@ -38,14 +36,10 @@ function BasicInfo(props) {
const [assignorModalVisible, setAssignorModalVisible] = useState(false); // 指派对象弹窗显隐
const [collaboratorModalVisible, setCollaboratorModalVisible] = useState(false); // 协同者弹窗显隐
useEffect(() => {
updateCover();
}, [coverId]);
// 使用默认封面图
function handleResetCoverUrl() {
message.success('已替换为默认图');
props.onChange('coverUrl', defaultCover);
props.onChange('coverUrl', { fileUrl: defaultCover });
}
// 从云盘选择封面
......@@ -56,17 +50,13 @@ function BasicInfo(props) {
function getSignature(blob, fileName) {
Upload.uploadBlobToOSS(blob, 'cover' + new Date().valueOf(), null, 'signInfo').then((signInfo) => {
setCoverClicpPath(signInfo.fileUrl);
setCoverId(signInfo.resourceId);
const { fileUrl, resourceId } = signInfo;
setImgClipVisible(false);
setShowSelectFileModal(false);
props.onChange('coverUrl', { fileUrl, resourceId });
});
}
function updateCover() {
setShowSelectFileModal(false);
props.onChange('coverUrl', coverClicpPath || coverUrl || defaultCover);
}
// 禁选日期
function disabledDate(current) {
return current && current < moment().startOf('day');
......@@ -104,15 +94,19 @@ function BasicInfo(props) {
}
function confirmAddCollaborator(data) {
props.onChange('helpStoreUserIds', data);
const helpStoreUserIds = data.map((item) => item.userId);
props.onChange('helpStoreUserIds', helpStoreUserIds);
}
function removeSelectedCollaborator(tag, index) {
console.log('vaaaaa', tag, index);
const _helpStoreUserIds = helpStoreUserIds.filter((item) => item !== tag);
console.log(_helpStoreUserIds);
props.onChange('helpStoreUserIds', _helpStoreUserIds);
}
function test(data) {
console.log(data);
props.onChange('introduce', data);
// props.onChange('introduce', data);
}
return (
<div className='basic-info__form'>
......@@ -152,14 +146,18 @@ function BasicInfo(props) {
</FormItem>
<FormItem label='培训时间'>
<div className='duration__wrap'>
<Radio.Group value={timeType} onChange={(e) => props.onChange('timeType', e.target.value)}>
<Radio.Group
value={timeType}
onChange={(e) => {
props.onChange('timeType', e.target.value);
}}>
<Space direction='vertical' size={16}>
<Radio value='VALIDITY'>
<Radio value='FOREVER'>
永久有效<span className='tips'>设置为“永久有效”,发布后任务开始生效,取消发布后失效</span>
</Radio>
<Radio value='FIXED_DURATION'>
<Radio value='VALIDITY'>
固定时间段
{timeType === 'FIXED_DURATION' && (
{timeType === 'VALIDITY' && (
<div className='picker-box'>
<FormItem
validateStatus={startCheck && !startTime && !endTime ? 'error' : ''}
......@@ -310,10 +308,10 @@ function BasicInfo(props) {
isIntro={true}
placeholder='请输入培训目的'
detail={{
content: instro,
content: introduce,
}}
onChange={(val) => {
// changeIntro(val);
onChange={(val, length) => {
test(val);
}}
/>
</FormItem>
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-01 17:28:30
* @LastEditors: yuananting
* @LastEditTime: 2021-08-04 16:13:46
* @LastEditTime: 2021-08-09 14:25:18
* @Description: 新建培训任务-关联课程抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -352,7 +352,6 @@ class RelatedCourseDrawer extends Component {
key: 'courseChapterNum',
dataIndex: 'courseChapterNum',
width: '20%',
align: 'right',
render: (val, record) => {
return <span>{val || 1}</span>;
},
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-05 14:21:19
* @LastEditTime: 2021-08-09 13:56:24
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -53,6 +53,7 @@ class TrainContent extends Component {
constructor(props) {
super(props);
this.state = {
basicInfo: props.basicInfo,
stageList: props.stageList,
finishStandard: props.finishStandard,
showCourseDrawer: false,
......@@ -476,7 +477,7 @@ class TrainContent extends Component {
};
render() {
const { stageList, showCourseDrawer, showExamDrawer, expiredCourseList, showStandardDetail, finishStandard } = this.state;
const { stageList, showCourseDrawer, showExamDrawer, expiredCourseList, showStandardDetail, finishStandard, basicInfo } = this.state;
const { percentCompleteLive, percentCompleteVideo, percentCompletePicture } = finishStandard;
const { startCheck } = this.props;
......@@ -495,7 +496,7 @@ class TrainContent extends Component {
</div>
)}
{showCourseDrawer && <RelatedCourseDrawer data={stageList} onClose={this.onCloseCourseDrawer} onSelect={this.confirmSelectCourse} />}
{showExamDrawer && <RelatedExamDrawer onClose={this.onCloseExamDrawer} />}
{showExamDrawer && <RelatedExamDrawer basicInfo={basicInfo} onClose={this.onCloseExamDrawer} />}
</div>
<div className='expired-info__wrap'>
<div className='module-title'>失效课程</div>
......
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-28 14:56:52
* @LastEditors: yuananting
* @LastEditTime: 2021-08-05 16:33:02
* @LastEditTime: 2021-08-09 11:13:14
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......@@ -12,12 +12,13 @@ import { Tooltip, Checkbox, Dropdown, Radio, Button, Space, Badge } from 'antd';
import './TrainList.less';
import { XMTable, PageControl } from '@/components';
import User from '@/common/js/user';
import ENUM from '../../enum';
function TrainList(props) {
const {
query: { issueState, myAssist, current, size },
totalCount,
match
match,
} = props;
function renderMoreOperate(item) {
......@@ -36,8 +37,8 @@ function TrainList(props) {
const columns = [
{
title: '培训任务',
key: 'planName',
dataIndex: 'planName',
key: 'taskName',
dataIndex: 'taskName',
width: '18%',
fixed: 'left',
render: (val, record) => {
......@@ -45,8 +46,8 @@ function TrainList(props) {
<div className='train-task-name'>
<img className='train-cover' src={record.coverUrl || 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'} alt='' />
<Choose>
<When condition={record.planName.length > 25}>
<Tooltip title={record.planName}>
<When condition={record.taskName?.length > 25}>
<Tooltip title={record.taskName}>
<div className='train-name'>{val}</div>
</Tooltip>
</When>
......@@ -60,18 +61,23 @@ function TrainList(props) {
},
{
title: '任务状态',
width: '10%',
key: 'status',
dataIndex: 'status',
render: (val, record) => {
return <span>{'未开始'}</span>;
width: '12%',
key: 'taskState',
dataIndex: 'taskState',
render: (val) => {
return (
<div className='task-state'>
<span className='status-point' style={{ backgroundColor: ENUM.trainStatus[val || 'UN_START'].color }}></span>
<span>{ENUM.trainStatus[val || 'UN_START'].text}</span>
</div>
);
},
},
{
title: '任务数',
width: '8%',
key: 'courseNum',
dataIndex: 'courseNum',
key: 'contentNum',
dataIndex: 'contentNum',
render: (val, record) => {
return <span>{val}</span>;
},
......@@ -82,8 +88,19 @@ function TrainList(props) {
key: 'cultureCustomerNum',
dataIndex: 'cultureCustomerNum',
sorter: true,
render: (val) => {
return <span style={{ color: '#2966FF' }}>{val}</span>;
render: (val, record) => {
return (
<Tooltip
title={
<div>
<div>未完成:{record.startingCustomerNum}</div>
<div>已完成:{record.finishCustomerNum}</div>
<div>已逾期:{record.overdueCustomerNum}</div>
</div>
}>
<span style={{ color: '#2966FF' }}>{val}</span>
</Tooltip>
);
},
},
{
......@@ -106,20 +123,27 @@ function TrainList(props) {
</span>
),
width: '10%',
key: 'rate',
dataIndex: 'rate',
key: 'finishPercent',
dataIndex: 'finishPercent',
sorter: true,
render: (val) => {
return <span>100%</span>;
return <span>{val}%</span>;
},
},
{
title: '培训时间',
width: '14%',
key: 'created',
dataIndex: 'created',
render: (val) => {
return <span style={{ whiteSpace: 'nowrap' }}>{window.formatDate('YYYY-MM-DD H:i', val)}</span>;
key: 'trainTime',
dataIndex: 'trainTime',
render: (val, record) => {
if (record.timeType === 'FOREVER') {
return <span>不限时</span>;
}
return (
<span style={{ whiteSpace: 'nowrap' }}>
{window.formatDate('YYYY-MM-DD H:i', record.startTime)}~{window.formatDate('YYYY-MM-DD H:i', record.endTime)}
</span>
);
},
},
{
......@@ -161,9 +185,11 @@ function TrainList(props) {
render: (val, record) => {
return (
<div className='operate'>
<div className='operate__item' onClick={() => {
props.history.push(`${match.path}/data?planId=${record.planId}`)
}}>
<div
className='operate__item'
onClick={() => {
props.history.push(`${match.path}/data?planId=${record.planId}`);
}}>
数据
</div>
<span className='split'> | </span>
......@@ -200,6 +226,64 @@ function TrainList(props) {
props.onChange(_query);
}
function handleChangeTable(pagination, filters, sorter) {
const { columnKey, order } = sorter;
const { query } = props;
let _columnKey;
let _order;
if (columnKey == 'cultureCustomerNum' && order === 'ascend') {
// 按学习人数升序排序
_columnKey = 'CUSTOMER_NUM';
_order = 'SORT_ASC';
}
if (columnKey == 'cultureCustomerNum' && order === 'descend') {
// 按学习人数降序排序
_columnKey = 'CUSTOMER_NUM';
_order = 'SORT_DESC';
}
if (columnKey == 'finishPercent' && order === 'ascend') {
// 按完成率升序排序
_columnKey = 'FINISH_PERCENT';
_order = 'SORT_ASC';
}
if (columnKey == 'finishPercent' && order === 'descend') {
// 按完成率降序排序
_columnKey = 'FINISH_PERCENT';
_order = 'SORT_DESC';
}
if (columnKey === 'created' && order === 'ascend') {
// 按创建时间升序排序
_columnKey = 'CREATED';
_order = 'SORT_ASC';
}
if (columnKey === 'created' && order === 'descend') {
// 按创建时间降序排序
_columnKey = 'CREATED';
_order = 'SORT_DESC';
}
if (columnKey === 'updated' && order === 'ascend') {
// 按更新时间升序排序
_columnKey = 'UPDATED';
_order = 'SORT_ASC';
}
if (columnKey === 'updated' && order === 'descend') {
// 按更新时间降序排序
_columnKey = 'UPDATED';
_order = 'SORT_DESC';
}
const _query = {
...query,
sortMap: {},
};
_query.sortMap[_columnKey] = _order;
props.onChange(_query);
}
function handleCreatePlan() {
window.RCHistory.push({
pathname: '/create-train-task?type=add',
......@@ -237,7 +321,7 @@ function TrainList(props) {
dataSource={props.trainListData}
columns={parseColumns()}
pagination={false}
// onChange={handleChangeTable}
onChange={handleChangeTable}
bordered
size='middle'
scroll={{ x: 1600 }}
......
......@@ -29,7 +29,6 @@
border-radius: 2px;
margin-right: 8px;
}
.train-name {
width: 188px;
overflow: hidden;
......@@ -40,6 +39,18 @@
height: 40px;
}
}
.task-state {
* {
vertical-align: middle;
display: inline-block;
}
.status-point {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 4px;
}
}
.operate {
display: flex;
......
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