Commit f95a3d4e by yuananting

feat:课程改造培训计划部分更改

parent 62d535e8
/*
* @Author: yuananting
* @Date: 2021-07-05 10:47:19
* @LastEditors: yuananting
* @LastEditTime: 2021-07-05 11:00:28
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import { message } from 'antd'; import { message } from 'antd';
import React from 'react'; import React from 'react';
import E from 'wangeditor'; import E from 'wangeditor';
...@@ -9,25 +18,23 @@ const { BtnMenu } = E; ...@@ -9,25 +18,23 @@ const { BtnMenu } = E;
class GraphicsEditor extends React.Component { class GraphicsEditor extends React.Component {
constructor(props) { constructor(props) {
super(props) super(props);
this.state = { this.state = {
editorId: window.random_string(16), editorId: window.random_string(16),
textLength: 0, textLength: 0,
showSelectImageModal: false, showSelectImageModal: false,
showSelectVideoModal: false, showSelectVideoModal: false,
diskList: [], diskList: [],
} };
this.editorInt = null; this.editorInt = null;
} }
componentDidMount() { componentDidMount() {
this.renderEditor() this.renderEditor();
this.resetIndex(true); this.resetIndex(true);
this.initBus(); this.initBus();
} }
componentWillUnmount() { componentWillUnmount() {
this.resetIndex(); this.resetIndex();
this.removeBus(); this.removeBus();
...@@ -38,7 +45,7 @@ class GraphicsEditor extends React.Component { ...@@ -38,7 +45,7 @@ class GraphicsEditor extends React.Component {
const leftDom = document.querySelector('.left-container'); const leftDom = document.querySelector('.left-container');
// topDom.style.zIndex = bool ? 'auto' : 112; // topDom.style.zIndex = bool ? 'auto' : 112;
// leftDom.style.zIndex = bool ? 'auto' : 2; // leftDom.style.zIndex = bool ? 'auto' : 2;
} };
renderEditor() { renderEditor() {
const { editorId } = this.state; const { editorId } = this.state;
...@@ -50,17 +57,15 @@ class GraphicsEditor extends React.Component { ...@@ -50,17 +57,15 @@ class GraphicsEditor extends React.Component {
`<div class="w-e-menu" data-title="图片"> `<div class="w-e-menu" data-title="图片">
<i class="w-e-icon-image"></i> <i class="w-e-icon-image"></i>
</div>` </div>`
) );
super($elem, editor) super($elem, editor);
} }
// 菜单点击事件 // 菜单点击事件
clickHandler() { clickHandler() {
Bus.trigger(`graphicsEditorImage${isIntro ? '' : 'Content'}`) Bus.trigger(`graphicsEditorImage${isIntro ? '' : 'Content'}`);
} }
tryChangeActive() { tryChangeActive() {}
}
} }
class VideoMenu extends BtnMenu { class VideoMenu extends BtnMenu {
...@@ -70,97 +75,95 @@ class GraphicsEditor extends React.Component { ...@@ -70,97 +75,95 @@ class GraphicsEditor extends React.Component {
`<div class="w-e-menu" data-title="视频"> `<div class="w-e-menu" data-title="视频">
<i class="w-e-icon-play"></i> <i class="w-e-icon-play"></i>
</div>` </div>`
) );
super($elem, editor) super($elem, editor);
} }
// 菜单点击事件 // 菜单点击事件
clickHandler() { clickHandler() {
Bus.trigger('graphicsEditorVideo') Bus.trigger('graphicsEditorVideo');
} }
tryChangeActive() { tryChangeActive() {}
}
} }
this.editorInt = new E(`#editor${editorId}`); this.editorInt = new E(`#editor${editorId}`);
this.editorInt.config.focus = false; this.editorInt.config.focus = false;
this.editorInt.config.showFullScreen = !isIntro this.editorInt.config.showFullScreen = !isIntro;
this.editorInt.menus.extend('xmimage', ImageMenu); this.editorInt.menus.extend('xmimage', ImageMenu);
!isIntro && this.editorInt.menus.extend('xmvideo', VideoMenu); !isIntro && this.editorInt.menus.extend('xmvideo', VideoMenu);
this.editorInt.config.menus = isIntro ? this.editorInt.config.menus = isIntro
[ ? ['head', 'bold', 'fontSize', 'fontName', 'italic', 'underline', 'strikeThrough', 'foreColor', 'backColor', 'list', 'justify', 'emoticon', 'xmimage']
'head',
'bold',
'fontSize',
'fontName',
'italic',
'underline',
'strikeThrough',
'foreColor',
'backColor',
'list',
'justify',
'emoticon',
'xmimage',
]
: [ : [
'head', 'head',
'bold', 'bold',
'fontSize', 'fontSize',
'fontName', 'fontName',
'italic', 'italic',
'underline', 'underline',
'strikeThrough', 'strikeThrough',
'indent', 'indent',
'lineHeight', 'lineHeight',
'foreColor', 'foreColor',
'backColor', 'backColor',
'link', 'link',
'list', 'list',
'todo', 'todo',
'justify', 'justify',
'quote', 'quote',
'emoticon', 'emoticon',
'xmimage', 'xmimage',
'xmvideo', 'xmvideo',
'table', 'table',
'splitLine', 'splitLine',
'undo', 'undo',
'redo', 'redo',
]; ];
this.editorInt.config.emotions = [ this.editorInt.config.emotions = [
{ {
title: 'emoji', title: 'emoji',
type: 'emoji', type: 'emoji',
content: ['😀', '😃', '😄', '😁', '😆', '😅', '😂', '😊', '🙂', '🙃', '😉', '😓', '😅', '😪', '🤔', '😬', '🤐'] content: ['😀', '😃', '😄', '😁', '😆', '😅', '😂', '😊', '🙂', '🙃', '😉', '😓', '😅', '😪', '🤔', '😬', '🤐'],
} },
] ];
this.editorInt.config.zIndex = 1; this.editorInt.config.zIndex = 1;
this.editorInt.config.pasteFilterStyle = false; this.editorInt.config.pasteFilterStyle = false;
this.editorInt.config.pasteIgnoreImg = true; this.editorInt.config.pasteIgnoreImg = true;
// 自定义处理粘贴的文本内容 // 自定义处理粘贴的文本内容
this.editorInt.config.pasteTextHandle = function (content) { this.editorInt.config.pasteTextHandle = (content) => {
if (content == '' && !content) return '' if (content == '' && !content) return '';
var str = content var str1 = content; // 去除所有特殊字符
str = str.replace(/<xml>[\s\S]*?<\/xml>/ig, '') str1 = str1.replace(/<xml>[\s\S]*?<\/xml>/gi, '');
str = str.replace(/<style>[\s\S]*?<\/style>/ig, '') str1 = str1.replace(/<style>[\s\S]*?<\/style>/gi, '');
str = str.replace(/[ | ]*\n/g, '\n') str1 = str1.replace(/<\/?[^>]*>/g, '');
str = str.replace(/\&nbsp\;/ig, ' ') str1 = str1.replace(/[ | ]*\n/g, '\n');
return str str1 = str1.replace(/\&nbsp\;/gi, ' ');
} str1 = str1.replace(/[\r\n]/g, '');
str1 = str1.replace(/<\/?a.*?>/g, '');
var str2 = content; // 保留空格和换行的其他字符
str2 = str2.replace(/<xml>[\s\S]*?<\/xml>/gi, '');
str2 = str2.replace(/<style>[\s\S]*?<\/style>/gi, '');
str2 = str2.replace(/<\/?a.*?>/g, '');
const videoCount = ((content || '').match(/<iframe/g) || []).length;
const imageCount = ((content || '').match(/<img/g) || []).length;
const textLength = this.editorInt.txt.text().length + str1.length + videoCount + imageCount;
if (textLength > maxLimit) {
message.warning(`内容过长,不能超过${maxLimit}字`);
}
return str2;
};
this.editorInt.config.onchange = (html) => { this.editorInt.config.onchange = (html) => {
const videoCount = ((html || '').match(/<iframe/g) || []).length; const videoCount = ((html || '').match(/<iframe/g) || []).length;
const imageCount = ((html || '').match(/<img/g) || []).length; const imageCount = ((html || '').match(/<img/g) || []).length;
const textLength = this.editorInt.txt.text().replace(/\&nbsp\;/ig, ' ').length + videoCount + imageCount; const textLength = this.editorInt.txt.text().replace(/\&nbsp\;/gi, ' ').length + videoCount + imageCount;
this.setState({ textLength }, () => { this.setState({ textLength }, () => {
if (textLength > maxLimit) { if (textLength > maxLimit) {
// message.warning('超过字数限定'); // message.warning('超过字数限定');
} }
onChange(html, this.state.textLength); onChange(html, this.state.textLength);
}) });
} };
this.editorInt.create(); this.editorInt.create();
this.editorInt.txt.html(detail.content); this.editorInt.txt.html(detail.content);
} }
...@@ -170,89 +173,91 @@ class GraphicsEditor extends React.Component { ...@@ -170,89 +173,91 @@ class GraphicsEditor extends React.Component {
const { ossUrl } = file || {}; const { ossUrl } = file || {};
if (!ossUrl) return null; if (!ossUrl) return null;
this.setState({ this.setState({
showSelectVideoModal: false showSelectVideoModal: false,
}) });
const { detail } = this.props; const { detail } = this.props;
this.editorInt && this.editorInt.txt.html(`${detail.content}<p style="width: 100%;padding-top: 56.25%;position: relative;"><iframe style="position: absolute;width: 100%;height: 100%;top: 0;left: 0;" src="${ossUrl}"></iframe><br/></p><p><br/></p>`) this.editorInt &&
} this.editorInt.txt.html(
`${detail.content}<p style="width: 100%;padding-top: 56.25%;position: relative;"><iframe style="position: absolute;width: 100%;height: 100%;top: 0;left: 0;" src="${ossUrl}"></iframe><br/></p><p><br/></p>`
);
};
handleSelectImage = (file) => { handleSelectImage = (file) => {
const { ossUrl } = file || {}; const { ossUrl } = file || {};
if (!ossUrl) return null; if (!ossUrl) return null;
this.setState({ this.setState({
showSelectImageModal: false showSelectImageModal: false,
}) });
const { detail } = this.props; const { detail } = this.props;
this.editorInt && this.editorInt.txt.html(`${detail.content}<p><img style="max-width: 100%;" src="${ossUrl}" /><br/><p>`) this.editorInt && this.editorInt.txt.html(`${detail.content}<p><img style="max-width: 100%;" src="${ossUrl}" /><br/><p>`);
} };
initBus = () => { initBus = () => {
const { isIntro } = this.props; const { isIntro } = this.props;
Bus.bind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage) Bus.bind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage);
!isIntro && Bus.bind('graphicsEditorVideo', this.uploadVideo) !isIntro && Bus.bind('graphicsEditorVideo', this.uploadVideo);
} };
removeBus = () => { removeBus = () => {
const { isIntro } = this.props; const { isIntro } = this.props;
Bus.unbind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage) Bus.unbind(`graphicsEditorImage${isIntro ? '' : 'Content'}`, this.uploadImage);
!isIntro && Bus.unbind('graphicsEditorVideo', this.uploadVideo) !isIntro && Bus.unbind('graphicsEditorVideo', this.uploadVideo);
} };
uploadImage = () => { uploadImage = () => {
this.setState({ showSelectImageModal: true }) this.setState({ showSelectImageModal: true });
} };
uploadVideo = () => { uploadVideo = () => {
this.setState({ showSelectVideoModal: true }) this.setState({ showSelectVideoModal: true });
} };
render() { render() {
const { const { editorId, textLength, showSelectImageModal, showSelectVideoModal, diskList } = this.state;
editorId, const { isIntro, maxLimit } = this.props;
textLength, return (
showSelectImageModal, <div className={`graphics-editor-container${isIntro ? ' introduce' : ''} ${textLength > maxLimit && 'warning'}`}>
showSelectVideoModal, <div className='editor-box' id={`editor${editorId}`}></div>
diskList, <div className='editor-tips'>
} = this.state; ({textLength > maxLimit ? <span style={{ color: 'red' }}>{textLength}</span> : textLength}/{maxLimit || 1000})
const { limitLength = 1000, isIntro, maxLimit } = this.props; </div>
return <div className={`graphics-editor-container${isIntro ? ' introduce' : ''} ${(textLength > maxLimit)&& 'warning'}`}> {textLength > maxLimit && <div className='editor-warning'>最多只能输入{maxLimit || 1000}</div>}
<div className="editor-box" id={`editor${editorId}`} ></div> {showSelectVideoModal && (
<div className="editor-tips">( {(textLength > maxLimit) ? <span style={{ color: 'red' }} >{textLength}</span> : textLength}/{maxLimit || 1000})</div> <SelectPrepareFileModal
{showSelectVideoModal && operateType='select'
<SelectPrepareFileModal selectTypeList={['MP4']}
operateType="select" accept='video/mp4'
selectTypeList={['MP4']} confirm={{
accept="video/mp4" title: '文件过大,无法上传',
confirm={{ content: '为保障学员的观看体验,上传的图文大小不能超过2G',
title: '文件过大,无法上传', }}
content: '为保障学员的观看体验,上传的图文大小不能超过2G', tooltip={'格式支持mp4,大小不超过2G'}
}} isOpen={showSelectVideoModal}
tooltip={'格式支持mp4,大小不超过2G'} diskList={diskList}
isOpen={showSelectVideoModal} addVideo={true}
diskList={diskList} onClose={() => {
addVideo={true} this.setState({ showSelectVideoModal: false });
onClose={() => { }}
this.setState({ showSelectVideoModal: false }) onSelect={this.handleSelectVideo}
}} />
onSelect={this.handleSelectVideo} )}
/> {showSelectImageModal && (
} <SelectPrepareFileModal
{showSelectImageModal && key='basic'
<SelectPrepareFileModal operateType='select'
key="basic" multiple={false}
operateType="select" accept='image/jpeg,image/png,image/jpg'
multiple={false} selectTypeList={['JPG', 'JPEG', 'PNG']}
accept="image/jpeg,image/png,image/jpg" tooltip='支持文件类型:jpg、jpeg、png'
selectTypeList={['JPG', 'JPEG', 'PNG']} isOpen={showSelectImageModal}
tooltip='支持文件类型:jpg、jpeg、png' onClose={() => {
isOpen={showSelectImageModal} this.setState({ showSelectImageModal: false });
onClose={() => { }}
this.setState({ showSelectImageModal: false }) onSelect={this.handleSelectImage}
}} />
onSelect={this.handleSelectImage} )}
/> </div>
} );
</div>
} }
} }
......
.graphics-editor-container { .graphics-editor-container {
border: 1px solid #E8E8E8; border: 1px solid #e8e8e8;
border-radius: 4px; border-radius: 4px;
width: 702px; width: 702px;
height: 510px; height: 510px;
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.w-e-toolbar { .w-e-toolbar {
background-color: #fff !important; background-color: #fff !important;
border: none !important; border: none !important;
border-bottom: 1px solid #E8E8E8 !important; border-bottom: 1px solid #e8e8e8 !important;
} }
.w-e-text-container { .w-e-text-container {
...@@ -38,6 +38,14 @@ ...@@ -38,6 +38,14 @@
color: #666; color: #666;
z-index: 1; z-index: 1;
} }
.editor-warning {
position: absolute;
right: 0;
top: 205px;
color: red;
}
.w-e-full-screen-editor { .w-e-full-screen-editor {
.w-e-text-container { .w-e-text-container {
height: ~'calc(100vh - 109px)' !important; height: ~'calc(100vh - 109px)' !important;
...@@ -50,7 +58,7 @@ ...@@ -50,7 +58,7 @@
} }
} }
&.warning{ &.warning {
border-color: red; border-color: red;
} }
} }
\ No newline at end of file
/* /*
* @Author: yuananting
* @Date: 2021-07-05 10:48:08
* @LastEditors: yuananting
* @LastEditTime: 2021-07-05 11:01:19
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
/*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: fusanqiasng * @LastEditors: yuananting
* @LastEditTime: 2021-06-01 15:20:33 * @LastEditTime: 2021-07-02 17:16:06
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -12,7 +21,7 @@ import { withRouter } from 'react-router-dom'; ...@@ -12,7 +21,7 @@ import { withRouter } from 'react-router-dom';
import SelectOperatorModal from '../modal/SelectOperatorModal'; import SelectOperatorModal from '../modal/SelectOperatorModal';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal'; import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import Upload from '@/core/upload'; import Upload from '@/core/upload';
// import PhotoClip from 'photoclip' import GraphicsEditor from '@/modules/course-manage/components/GraphicsEditor';
import './BasicInfo.less'; import './BasicInfo.less';
const { TextArea } = Input; const { TextArea } = Input;
...@@ -202,10 +211,14 @@ class BasicInfo extends React.Component { ...@@ -202,10 +211,14 @@ class BasicInfo extends React.Component {
this.props.onChange(field, _percentCompleteLive); this.props.onChange(field, _percentCompleteLive);
}; };
changeIntro = (value) => {
this.props.onChange('introduce', value);
};
render() { render() {
const { operatorModalVisible, showSelectFileModal, visible, hasImgReady, cutImageBlob } = this.state; const { operatorModalVisible, showSelectFileModal, visible, hasImgReady, cutImageBlob } = this.state;
const { data } = this.props; const { data } = this.props;
const { planName, coverUrl, instro, enableState, operateType, selectOperatorList, percentCompleteLive, percentCompleteVideo, percentCompletePicture } = const { planName, coverUrl, introduce, enableState, operateType, selectOperatorList, percentCompleteLive, percentCompleteVideo, percentCompletePicture } =
data; data;
// 当前是否使用的是默认图片 // 当前是否使用的是默认图片
const isDefaultCover = coverUrl === defaultCover; const isDefaultCover = coverUrl === defaultCover;
...@@ -226,10 +239,6 @@ class BasicInfo extends React.Component { ...@@ -226,10 +239,6 @@ class BasicInfo extends React.Component {
<div className='cover'> <div className='cover'>
<span className='label'>封面图:</span> <span className='label'>封面图:</span>
<div className='cover__wrap'> <div className='cover__wrap'>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} width='690' alt='' />
</div>
<div className='opt-btns'> <div className='opt-btns'>
<Button <Button
onClick={() => { onClick={() => {
...@@ -244,17 +253,32 @@ class BasicInfo extends React.Component { ...@@ -244,17 +253,32 @@ class BasicInfo extends React.Component {
</span> </span>
<div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div> <div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div>
</div> </div>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} width='690' alt='' />
</div>
</div> </div>
</div> </div>
<div className='introduction'> <div className='introduction'>
<span className='label'>简介:</span> <span className='label'>课程简介:</span>
<TextArea {/* <TextArea
placeholder='请输入培训计划简介' placeholder='请输入培训计划简介'
maxLength={200} maxLength={200}
style={{ width: '552px', height: '110px' }} style={{ width: '552px', height: '110px' }}
className='instro-textarea' className='instro-textarea'
value={instro} value={instro}
onChange={(e) => this.props.onChange('instro', e.target.value)} onChange={(e) => this.props.onChange('instro', e.target.value)}
/> */}
<GraphicsEditor
id='intro'
isIntro={true}
maxLimit={1000}
detail={{
content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}}
/> />
</div> </div>
<div className='wether-use'> <div className='wether-use'>
...@@ -270,8 +294,7 @@ class BasicInfo extends React.Component { ...@@ -270,8 +294,7 @@ class BasicInfo extends React.Component {
</div> </div>
<div> <div>
<div className='instro-text'> <div className='instro-text'>
<div>开启:此培训计划可以分享给学员进行学习</div> <div>{enableState === 'YES' ? '已开启,培训计划可正常分享给学员学习' : '已关闭,培训计划暂不进行分享和学习'}</div>
<div>关闭:此培训计划暂不可分享给学员进行学习,后续可开启</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -291,7 +314,7 @@ class BasicInfo extends React.Component { ...@@ -291,7 +314,7 @@ class BasicInfo extends React.Component {
onChange={(e) => { onChange={(e) => {
this.props.onChange('operateType', e.target.value); this.props.onChange('operateType', e.target.value);
}}> }}>
<Row style={{ marginBottom: '5px' }}> <Row style={{ marginBottom: '16px' }}>
<Col span={24}> <Col span={24}>
<Radio value='All_Operate'> <Radio value='All_Operate'>
所有运营师 所有运营师
...@@ -317,7 +340,7 @@ class BasicInfo extends React.Component { ...@@ -317,7 +340,7 @@ class BasicInfo extends React.Component {
选择运营师 选择运营师
</Button> </Button>
<span> <span>
已选择<span>{selectOperatorList.length}</span>名运营师 已选择 <span style={{ color: '#2966FF' }}>{selectOperatorList.length}</span> 名运营师
</span> </span>
</div> </div>
)} )}
...@@ -347,7 +370,7 @@ class BasicInfo extends React.Component { ...@@ -347,7 +370,7 @@ class BasicInfo extends React.Component {
<div className='live-standard-info'> <div className='live-standard-info'>
<span className='icon iconfont'>&#xe864;</span> <span className='icon iconfont'>&#xe864;</span>
<span className='instro'> <span className='instro'>
线上课单个课,学员学习进度达到 线上课单个课,学员学习进度达到
<Input <Input
width='40' width='40'
value={percentCompleteVideo} value={percentCompleteVideo}
...@@ -357,7 +380,7 @@ class BasicInfo extends React.Component { ...@@ -357,7 +380,7 @@ class BasicInfo extends React.Component {
onBlur={(e) => this.percentCompleteBlur(e, 'percentCompleteVideo')} onBlur={(e) => this.percentCompleteBlur(e, 'percentCompleteVideo')}
className='input-box' className='input-box'
/> />
%,即视为"已完成"学习 %,即课节视为"已完成"学习
</span> </span>
</div> </div>
<div className='live-standard-info'> <div className='live-standard-info'>
......
.plan-basic-info{ .plan-basic-info {
.label { .label {
width: 110px; width: 110px;
text-align: right; text-align: right;
display:inline-block; display: inline-block;
font-size:14px; font-size: 14px;
color:#666; color: #666;
.require { .require {
color: #EC4B35; color: #ec4b35;
} }
.iconfont{ .iconfont {
font-size:14px; font-size: 14px;
color:#BFBFBF; color: #bfbfbf;
}
}
.cover {
display: flex;
margin-top: 24px;
&__wrap {
position: relative;
.tag {
border-radius: 2px;
background: #d6d6d6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #fff;
position: absolute;
top: 8px;
left: 8px;
} }
} }
.cover { .img-content {
display: flex; position: relative;
margin-top: 16px; margin-top: 8px;
&__wrap { width: 299px;
position: relative; height: 169px;
display: flex; img {
.tag { width: 100%;
border-radius: 2px; height: 100%;
background: #D6D6D6; object-fit: contain;
font-size: 12px; }
height: 18px;
width: 52px;
text-align: center;
color: #FFF;
position: absolute;
top: 8px;
left: 8px;
}
}
.img-content {
margin-right: 20px;
width: 299px;
height: 169px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.opt-btns{
.default-btn {
margin:0 8px;
color: #2966FF;
cursor: pointer;
&.disabled {
color: #CCC;
cursor: not-allowed;
}
}
.tips{
margin-top:8px;
font-size:14px;
color:#999;
}
}
} }
.introduction{ .opt-btns {
margin-top:16px; .default-btn {
.instro-textarea{ margin: 0 8px;
vertical-align: top; color: #2966ff;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
} }
}
.tips {
margin-top: 8px;
font-size: 14px;
color: #999;
}
} }
.wether-use{ }
display:flex; .introduction {
margin-top:16px; display: flex;
.instro-text{ margin-top: 24px;
color:#999; .instro-textarea {
margin-left:12px; vertical-align: top;
}
.content{
display:flex;
}
} }
.view-range{ }
display:flex; .wether-use {
margin-top:16px; display: flex;
.label{ margin-top: 34px;
margin-top:2px; .instro-text {
} color: #999;
.instro-text{ margin-left: 12px;
color:#999;
margin-left:12px;
}
.choose-business{
margin-top:16px;
}
.playback__text{
margin-left:12px;
color:#999999;
}
} }
.done-standard{ .content {
display: flex; display: flex;
margin-top:22px; }
.standard-label{ }
margin-top:3px; .view-range {
} display: flex;
.live-standard-info{ margin-top: 24px;
margin-bottom:10px; .label {
} margin-top: 2px;
input{ }
display:inline-block; .instro-text {
width:90px; color: #999;
height:32px; margin-left: 12px;
} }
.icon{ .choose-business {
color:#A0A0A0; margin-top: 12px;
font-size:14px; .ant-btn {
margin-right:4px; margin-right: 12px;
}
.instro{
color:#333333;
font-size:14px;
}
.input-box{
width: 60px;
height: 32px;
border-radius: 4px;
border: 1px solid #E8E8E8;
color:#333333;
font-size:14px;
margin:0 2px;
} }
} }
.playback__text {
margin-left: 12px;
color: #999999;
}
}
.done-standard {
display: flex;
margin-top: 22px;
.standard-label {
margin-top: 3px;
}
.live-standard-info {
margin-bottom: 10px;
}
input {
display: inline-block;
width: 90px;
height: 32px;
}
.icon {
color: #a0a0a0;
font-size: 14px;
margin-right: 4px;
}
.instro {
color: #333333;
font-size: 14px;
}
.input-box {
width: 60px;
height: 32px;
border-radius: 4px;
border: 1px solid #e8e8e8;
color: #333333;
font-size: 14px;
margin: 0 2px;
}
}
} }
/* /*
* @Author: yuananting
* @Date: 2021-07-05 10:49:01
* @LastEditors: yuananting
* @LastEditTime: 2021-07-05 11:02:04
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
/*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-20 16:45:51 * @Date: 2021-02-20 16:45:51
* @LastEditors: fusanqiasng * @LastEditors: yuananting
* @LastEditTime: 2021-05-24 15:15:06 * @LastEditTime: 2021-07-01 17:16:50
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react' import React from 'react';
import { Input, Form, Modal } from 'antd' import { Input, Form, Modal } from 'antd';
import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc' import { sortableContainer, sortableElement, sortableHandle } from 'react-sortable-hoc';
import arrayMove from 'array-move' import arrayMove from 'array-move';
import RelatedCourseModal from '../modal/relatedCourseModal' import RelatedCourseModal from '../modal/relatedCourseModal';
import { withRouter } from 'react-router-dom' import { withRouter } from 'react-router-dom';
import './TrainingTask.less' import './TrainingTask.less';
const { confirm } = Modal const { confirm } = Modal;
const CourseType = { const CourseType = {
LIVE: { LIVE: {
text: '直播课' text: '直播课',
}, },
VOICE: { VOICE: {
text: '线上课' text: '线上课',
}, },
RECORD: { RECORD: {
text: '录播课' text: '录播课',
}, },
PICTURE: { PICTURE: {
text: '图文课' text: '图文课',
} },
} };
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
title: '待开播' title: '待开播',
}, },
STARTING: { STARTING: {
title: '直播中' title: '直播中',
}, },
FINISH: { FINISH: {
title: '回放' title: '回放',
}, },
EXPIRED: { EXPIRED: {
title: '未成功开课' title: '未成功开课',
} },
} };
const DragHandle = sortableHandle(() => ( const DragHandle = sortableHandle(() => (
<span className='operate__item'> <span className='operate__item'>
<span className='icon iconfont'>&#xe7cd;</span> <span className='icon iconfont'>&#xe7cd;</span>
<span className='text'>移动</span> <span className='text'>移动</span>
</span> </span>
)) ));
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>);
const SortableCourseItem = sortableElement((props) => <div {...props}>{props.courseitem}</div>) const SortableCourseItem = sortableElement((props) => <div {...props}>{props.courseitem}</div>);
const SortableCourseContainer = sortableContainer((props) => <div {...props}></div>) const SortableCourseContainer = sortableContainer((props) => <div {...props}></div>);
class TrainingTask extends React.Component { class TrainingTask extends React.Component {
constructor(props) { constructor(props) {
super(props) super(props);
this.state = { this.state = {
dataSource: this.props.data, dataSource: this.props.data,
selectedTaskIndex: 0, selectedTaskIndex: 0,
relatedCourseModalVisible: false relatedCourseModalVisible: false,
} };
} }
componentWillMount() {} componentWillMount() {}
componentWillReceiveProps(nextProps) {} componentWillReceiveProps(nextProps) {}
onTaskSortEnd = ({ oldIndex, newIndex }) => { onTaskSortEnd = ({ oldIndex, newIndex }) => {
const { dataSource } = this.state const { dataSource } = this.state;
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);
this.setState( this.setState(
{ {
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} }
} };
onCourseSortEnd = ({ oldIndex, newIndex }, parentIndex) => { onCourseSortEnd = ({ oldIndex, newIndex }, parentIndex) => {
const { dataSource } = this.state const { dataSource } = this.state;
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( this.setState(
{ {
dataSource: _dataSource dataSource: _dataSource,
}, },
() => { () => {
this.props.onChange(_dataSource) this.props.onChange(_dataSource);
} }
) );
} }
} };
addTask = () => { addTask = () => {
const { dataSource } = this.state const { dataSource } = this.state;
const taskObj = { const taskObj = {
taskName: '', taskName: '',
index: dataSource.length, index: dataSource.length,
type: 'input', type: 'input',
open: true, open: true,
courseList: [] courseList: [],
} };
const newData = [...dataSource, taskObj] const newData = [...dataSource, taskObj];
this.setState( this.setState(
{ {
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} };
handleRenameTaskName = (e, record) => { handleRenameTaskName = (e, record) => {
const { value } = e.target const { value } = e.target;
const { dataSource } = this.state const { dataSource } = this.state;
record.taskName = value record.taskName = value;
this.setState( this.setState(
{ {
dataSource dataSource,
}, },
() => { () => {
this.props.onChange(dataSource) this.props.onChange(dataSource);
} }
) );
} };
handleTaskNameBlur = (e, record) => { handleTaskNameBlur = (e, record) => {
const { value } = e.target const { value } = e.target;
const { dataSource } = this.state const { dataSource } = this.state;
let input = /^[\s]*$/ let input = /^[\s]*$/;
if (value && !input.test(value)) { if (value && !input.test(value)) {
record.type = 'text' record.type = 'text';
this.setState( this.setState(
{ {
dataSource dataSource,
}, },
() => { () => {
this.props.onChange(dataSource) this.props.onChange(dataSource);
} }
) );
} }
} };
handleRenameCourseName = (e, record) => { handleRenameCourseName = (e, record) => {
const { value } = e.target const { value } = e.target;
const { dataSource } = this.state const { dataSource } = this.state;
record.courseName = value record.courseName = value;
this.setState( this.setState(
{ {
dataSource dataSource,
}, },
() => { () => {
this.props.onChange(dataSource) this.props.onChange(dataSource);
} }
) );
} };
handleCourseNameBlur = (e, record) => { handleCourseNameBlur = (e, record) => {
const { value } = e.target const { value } = e.target;
const { dataSource } = this.state const { dataSource } = this.state;
let input = /^[\s]*$/ let input = /^[\s]*$/;
if (value && !input.test(value)) { if (value && !input.test(value)) {
record.type = 'text' record.type = 'text';
this.setState( this.setState(
{ {
dataSource dataSource,
}, },
() => { () => {
this.props.onChange(dataSource) this.props.onChange(dataSource);
} }
) );
} }
} };
handleDeleteTask = (index) => { handleDeleteTask = (index) => {
return confirm({ return confirm({
title: '删除任务', title: '删除任务',
...@@ -191,23 +200,23 @@ class TrainingTask extends React.Component { ...@@ -191,23 +200,23 @@ class TrainingTask extends React.Component {
okType: 'danger', okType: 'danger',
cancelText: '取消', cancelText: '取消',
onOk: () => { onOk: () => {
this.handleConfirmDeleteTask(index) this.handleConfirmDeleteTask(index);
} },
}) });
} };
handleConfirmDeleteTask = (index) => { handleConfirmDeleteTask = (index) => {
const { dataSource } = this.state const { dataSource } = this.state;
const newData = [...dataSource] const newData = [...dataSource];
newData.splice(index, 1) newData.splice(index, 1);
this.setState( this.setState(
{ {
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} };
handleDeleteCourse = (parentIndex, index) => { handleDeleteCourse = (parentIndex, index) => {
return confirm({ return confirm({
...@@ -218,82 +227,82 @@ class TrainingTask extends React.Component { ...@@ -218,82 +227,82 @@ class TrainingTask extends React.Component {
okType: 'danger', okType: 'danger',
cancelText: '取消', cancelText: '取消',
onOk: () => { onOk: () => {
this.handleConfirmDeleteCourse(parentIndex, index) this.handleConfirmDeleteCourse(parentIndex, index);
} },
}) });
} };
handleConfirmDeleteCourse = (parentIndex, index) => { handleConfirmDeleteCourse = (parentIndex, index) => {
const { dataSource } = this.state const { dataSource } = this.state;
const newData = [...dataSource] const newData = [...dataSource];
const selectData = [...newData[parentIndex].courseList] const selectData = [...newData[parentIndex].courseList];
selectData.splice(index, 1) selectData.splice(index, 1);
newData[parentIndex].courseList = selectData newData[parentIndex].courseList = selectData;
this.setState( this.setState(
{ {
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} };
showRelatedCourseModal = (index) => { showRelatedCourseModal = (index) => {
this.setState({ this.setState({
selectedTaskIndex: index, selectedTaskIndex: index,
relatedCourseModalVisible: true relatedCourseModalVisible: true,
}) });
} };
closeRelatedCourseModal = (index) => { closeRelatedCourseModal = (index) => {
this.setState({ this.setState({
relatedCourseModalVisible: false relatedCourseModalVisible: false,
}) });
} };
confirmSelectCourse = (selectList) => { confirmSelectCourse = (selectList) => {
console.log('selectList', selectList) console.log('selectList', selectList);
const { selectedTaskIndex } = this.state const { selectedTaskIndex } = this.state;
const { dataSource } = this.state const { dataSource } = this.state;
const newData = [...dataSource] const newData = [...dataSource];
const selectData = [...newData[selectedTaskIndex].courseList] const selectData = [...newData[selectedTaskIndex].courseList];
const _selectData = [...selectData, ...selectList] const _selectData = [...selectData, ...selectList];
newData[selectedTaskIndex].courseList = _selectData newData[selectedTaskIndex].courseList = _selectData;
this.setState( this.setState(
{ {
relatedCourseModalVisible: false, relatedCourseModalVisible: false,
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} };
openOrCloseTask = (index) => { openOrCloseTask = (index) => {
const { dataSource } = this.state const { dataSource } = this.state;
const newData = [...dataSource] const newData = [...dataSource];
newData[index].open = !newData[index].open newData[index].open = !newData[index].open;
this.setState( this.setState(
{ {
dataSource: newData dataSource: newData,
}, },
() => { () => {
this.props.onChange(newData) this.props.onChange(newData);
} }
) );
} };
handleValidatorTaskName = (rule, value) => { handleValidatorTaskName = (rule, value) => {
let input = /^[\s]*$/ let input = /^[\s]*$/;
if (input.test(value) || !value) { if (input.test(value) || !value) {
return Promise.reject(new Error('请输入任务名称')) return Promise.reject(new Error('请输入任务名称'));
} }
return Promise.resolve() return Promise.resolve();
} };
handleValidatorCourseName = (rule, value) => { handleValidatorCourseName = (rule, value) => {
let input = /^[\s]*$/ let input = /^[\s]*$/;
if (input.test(value) || !value) { if (input.test(value) || !value) {
return Promise.reject(new Error('请输入课程名称')) return Promise.reject(new Error('请输入课程名称'));
} }
return Promise.resolve() return Promise.resolve();
} };
renderTaskItem = (record, index) => { renderTaskItem = (record, index) => {
return ( return (
...@@ -314,8 +323,8 @@ class TrainingTask extends React.Component { ...@@ -314,8 +323,8 @@ class TrainingTask extends React.Component {
name={['taskName']} name={['taskName']}
rules={[ rules={[
{ {
validator: (rule, value) => this.handleValidatorTaskName(rule, value) validator: (rule, value) => this.handleValidatorTaskName(rule, value),
} },
]}> ]}>
<Input <Input
className='task-name-input' className='task-name-input'
...@@ -323,10 +332,10 @@ class TrainingTask extends React.Component { ...@@ -323,10 +332,10 @@ class TrainingTask extends React.Component {
placeholder='请输入任务名称(20字以内)' placeholder='请输入任务名称(20字以内)'
maxLength={20} maxLength={20}
onChange={(e) => { onChange={(e) => {
this.handleRenameTaskName(e, record) this.handleRenameTaskName(e, record);
}} }}
onBlur={(e) => { onBlur={(e) => {
this.handleTaskNameBlur(e, record) this.handleTaskNameBlur(e, record);
}} }}
/> />
</Form.Item> </Form.Item>
...@@ -346,9 +355,9 @@ class TrainingTask extends React.Component { ...@@ -346,9 +355,9 @@ class TrainingTask extends React.Component {
<span <span
className='operate__item' className='operate__item'
onClick={() => { onClick={() => {
const { dataSource } = this.state const { dataSource } = this.state;
record.type = 'input' record.type = 'input';
this.setState({ dataSource }) this.setState({ dataSource });
}}> }}>
<span className='icon iconfont'>&#xe6f5;</span> <span className='icon iconfont'>&#xe6f5;</span>
<span className='text'>重命名</span> <span className='text'>重命名</span>
...@@ -356,7 +365,7 @@ class TrainingTask extends React.Component { ...@@ -356,7 +365,7 @@ class TrainingTask extends React.Component {
<span <span
className='operate__item' className='operate__item'
onClick={() => { onClick={() => {
this.handleDeleteTask(index) this.handleDeleteTask(index);
}}> }}>
<span className='icon iconfont'>&#xe6f6;</span> <span className='icon iconfont'>&#xe6f6;</span>
<span className='text'>删除</span> <span className='text'>删除</span>
...@@ -377,7 +386,7 @@ class TrainingTask extends React.Component { ...@@ -377,7 +386,7 @@ class TrainingTask extends React.Component {
<span <span
className='add-course-btn-disabled' className='add-course-btn-disabled'
onClick={() => { onClick={() => {
this.showRelatedCourseModal(index) this.showRelatedCourseModal(index);
}}> }}>
<span>+</span> <span>+</span>
<span>关联课程</span> <span>关联课程</span>
...@@ -387,7 +396,7 @@ class TrainingTask extends React.Component { ...@@ -387,7 +396,7 @@ class TrainingTask extends React.Component {
<span <span
className='add-course-btn' className='add-course-btn'
onClick={() => { onClick={() => {
this.showRelatedCourseModal(index) this.showRelatedCourseModal(index);
}}> }}>
<span>+</span> <span>+</span>
<span>关联课程</span> <span>关联课程</span>
...@@ -398,9 +407,10 @@ class TrainingTask extends React.Component { ...@@ -398,9 +407,10 @@ class TrainingTask extends React.Component {
</div> </div>
)} )}
</div> </div>
) );
} };
renderCourseItem = (record, index, parentIndex) => { renderCourseItem = (record, index, parentIndex) => {
console.log(record);
return ( return (
<div className='plan-course-sort-item'> <div className='plan-course-sort-item'>
<div className='course-info'> <div className='course-info'>
...@@ -414,8 +424,8 @@ class TrainingTask extends React.Component { ...@@ -414,8 +424,8 @@ class TrainingTask extends React.Component {
name={['courseName']} name={['courseName']}
rules={[ rules={[
{ {
validator: (rule, value) => this.handleValidatorCourseName(rule, value) validator: (rule, value) => this.handleValidatorCourseName(rule, value),
} },
]}> ]}>
<Input <Input
className='course-name-input' className='course-name-input'
...@@ -423,10 +433,10 @@ class TrainingTask extends React.Component { ...@@ -423,10 +433,10 @@ class TrainingTask extends React.Component {
placeholder='请输入课程名称(40字以内)' placeholder='请输入课程名称(40字以内)'
maxLength={40} maxLength={40}
onChange={(e) => { onChange={(e) => {
this.handleRenameCourseName(e, record) this.handleRenameCourseName(e, record);
}} }}
onBlur={(e) => { onBlur={(e) => {
this.handleCourseNameBlur(e, record) this.handleCourseNameBlur(e, record);
}} }}
/> />
</Form.Item> </Form.Item>
...@@ -441,6 +451,7 @@ class TrainingTask extends React.Component { ...@@ -441,6 +451,7 @@ class TrainingTask extends React.Component {
{record.courseState === 'EXPIRED' && <span className='icon iconfont tip'>&#xe834;</span>} {record.courseState === 'EXPIRED' && <span className='icon iconfont tip'>&#xe834;</span>}
{record.courseType === 'LIVE' && <span className='course-state'>{courseStateShow[record.courseState].title}</span>} {record.courseType === 'LIVE' && <span className='course-state'>{courseStateShow[record.courseState].title}</span>}
{record.courseType === 'VOICE' && <span>(共{record.courseChapterNum || 1}小节)</span>}
</div> </div>
<div className='course-operate'> <div className='course-operate'>
<DragHandle /> <DragHandle />
...@@ -448,18 +459,18 @@ class TrainingTask extends React.Component { ...@@ -448,18 +459,18 @@ class TrainingTask extends React.Component {
<span <span
className='operate__item' className='operate__item'
onClick={() => { onClick={() => {
this.handleDeleteCourse(parentIndex, index) this.handleDeleteCourse(parentIndex, index);
}}> }}>
<span className='icon iconfont'>&#xe6f6;</span> <span className='icon iconfont'>&#xe6f6;</span>
<span className='text'>删除</span> <span className='text'>删除</span>
</span> </span>
</div> </div>
</div> </div>
) );
} };
render() { render() {
const { dataSource, selectedTaskIndex, relatedCourseModalVisible } = this.state const { dataSource, selectedTaskIndex, relatedCourseModalVisible } = this.state;
console.log('dataSource', dataSource) console.log('dataSource', dataSource);
return ( return (
<div className='training-task'> <div className='training-task'>
<SortableTaskContainer useDragHandle disableAutoscroll helperClass='row-dragging' onSortEnd={this.onTaskSortEnd} className='plan-task-sort-container'> <SortableTaskContainer useDragHandle disableAutoscroll helperClass='row-dragging' onSortEnd={this.onTaskSortEnd} className='plan-task-sort-container'>
...@@ -494,8 +505,8 @@ class TrainingTask extends React.Component { ...@@ -494,8 +505,8 @@ class TrainingTask extends React.Component {
/> />
)} )}
</div> </div>
) );
} }
} }
export default withRouter(TrainingTask) export default withRouter(TrainingTask);
/*
* @Author: yuananting
* @Date: 2021-07-05 10:50:30
* @LastEditors: yuananting
* @LastEditTime: 2021-07-05 11:05:31
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from 'react'; import React from 'react';
import {Table, Modal,Input} from 'antd'; import { Table, Modal, Input } from 'antd';
import { PageControl } from "@/components"; import PlanService from '@/domains/plan-domain/planService';
import PlanService from '@/domains/plan-domain/planService' import User from '@/common/js/user';
import User from '@/common/js/user'
import './UserLearnDetailModal.less'; import './UserLearnDetailModal.less';
import _ from "underscore"; import _ from 'underscore';
const { Search } = Input;
const defaultCover = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png'; const defaultCover = 'https://image.xiaomaiketang.com/xm/YNfi45JwFA.png';
const CourseType = { const CourseType = {
LIVE: { LIVE: {
text: "直播课" text: '直播课',
}, },
VOICE : { VOICE: {
text:"线上课" text: '线上课',
}, },
RECORD : { RECORD: {
text:'录播课' text: '录播课',
},
PICTURE: {
text: '图文课',
}, },
PICTURE:{
text:'图文课'
}
}; };
const courseStateShow = { const courseStateShow = {
UN_START: { UN_START: {
title: "待开播", title: '待开播',
}, },
STARTING: { STARTING: {
title: "直播中", title: '直播中',
}, },
FINISH: { FINISH: {
title: "回放", title: '回放',
}, },
EXPIRED: { EXPIRED: {
title: "未成功开课", title: '未成功开课',
}, },
}; };
class UserLearnDetailModal extends React.Component { class UserLearnDetailModal extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
planDataSource:{}, planDataSource: {},
taskDataSource:[], taskDataSource: [],
taskSize:10, taskSize: 10,
taskQuery: { taskQuery: {
current: 1, current: 1,
}, },
taskTotalCount:0, taskTotalCount: 0,
courseDataSource:[], courseDataSource: [],
storeCustomerName:'', storeCustomerName: '',
storeCustomerPhone:'' storeCustomerPhone: '',
}; };
} }
componentDidMount() { componentDidMount() {
this.getPlanCustomerDetail(); this.getPlanCustomerDetail();
} }
getPlanCustomerDetail = ()=>{ getPlanCustomerDetail = () => {
PlanService.getPlanCustomerDetail({ PlanService.getPlanCustomerDetail({
planId:getParameterByName("id"), planId: getParameterByName('id'),
storeCustomerId:this.props.storeCustomerId, storeCustomerId: this.props.storeCustomerId,
storeId:User.getStoreId() storeId: User.getStoreId(),
}).then((res) => { }).then((res) => {
const { const { storeCustomerName, storeCustomerPhone, planName, learnFinishPercentage, taskCustomerVOList, courseMediaVOS } = res.result;
storeCustomerName, let coverUrl;
storeCustomerPhone, courseMediaVOS.map((item) => {
if (item.contentType === 'COVER') {
coverUrl = item.mediaUrl;
}
return item;
});
const planDataSource = {
planName, planName,
learnFinishPercentage, learnFinishPercentage,
taskCustomerVOList, coverUrl: coverUrl || defaultCover,
courseMediaVOS, };
}=res.result; taskCustomerVOList.map((item) => {
let coverUrl; let videoClass =
courseMediaVOS.map((item) => { item.courseVOList &&
if(item.contentType === "COVER"){ item.courseVOList.filter((childItem, childIndex) => {
coverUrl = item.mediaUrl; return (childItem.courseType = 'VOICE');
} });
return item; videoClass.map((chapterItem, chapterIndex) => {
}) chapterItem.chapterList = [
const planDataSource = { {
planName, chapterName: '第一节1',
learnFinishPercentage, percentage: '80%',
coverUrl:coverUrl || defaultCover },
} {
this.setState({ chapterName: '第一节2',
storeCustomerName, percentage: '10%',
storeCustomerPhone, },
planDataSource, ];
taskDataSource:taskCustomerVOList return chapterItem;
}) });
}) return item;
} });
this.setState({
storeCustomerName,
storeCustomerPhone,
planDataSource,
taskDataSource: taskCustomerVOList,
});
});
};
parsePlanDataColumns = () => {
const columns = [
{
title: '培训计划名称',
key: 'planName',
dataIndex: 'planName',
width: '77%',
render: (val, record, index) => {
return (
<div className='record-name'>
<div className='img-con'>
<img src={record.coverUrl} />
</div>
<div>{record.planName}</div>
</div>
);
},
},
{
title: '学习进度',
key: 'learnFinishPercentage',
dataIndex: 'learnFinishPercentage',
render: (val, record, index) => {
return <div>{val}%</div>;
},
},
];
return columns;
};
parseTaskColumns = () => { parseTaskColumns = () => {
const columns = [ const columns = [
...@@ -95,134 +146,160 @@ class UserLearnDetailModal extends React.Component { ...@@ -95,134 +146,160 @@ class UserLearnDetailModal extends React.Component {
title: '培训任务', title: '培训任务',
key: 'taskName', key: 'taskName',
dataIndex: 'taskName', dataIndex: 'taskName',
render: (val, record,index) => { width: '68%',
render: (val, record, index) => {
return ( return (
<div className="taskName"> <div className='taskName'>
{index + 1}.{record.taskName} {index + 1}.{record.taskName}
</div> </div>
) );
} },
}, },
{ {
title: '学习进度', title: '学习进度',
key: 'learnFinishPercentage', key: 'learnFinishPercentage',
dataIndex: 'learnFinishPercentage', dataIndex: 'learnFinishPercentage',
width:167,
render: (val, record) => { render: (val, record) => {
return ( return <div className='task-learn-percentage'>{val === 100 ? <span>已完成</span> : <span>{val}%</span>}</div>;
<div className="task-learn-percentage"> },
{ val === 100 ?<span>已完成</span>:<span>{val}%</span>} },
</div>
)
}
}
]; ];
return columns; return columns;
} };
parseCoursecolumns = (parentIndex) => {
parseCourseColumns = (parentIndex) => {
const columns = [ const columns = [
{ {
title: '课程', title: '课程',
key: 'courseName', key: 'courseName',
dataIndex: 'courseName', dataIndex: 'courseName',
render: (val, record,index) => { width: '70%',
render: (val, record, index) => {
return ( return (
<div className="course-info"> <div className='course-info'>
<div> <div>
<span className="course-type">{CourseType[record.courseType].text}</span> <span className='course-type'>{CourseType[record.courseType].text}</span>
<span>{parentIndex + 1}.{index + 1}&nbsp;</span> <span>
{parentIndex + 1}.{index + 1}&nbsp;
</span>
</div> </div>
<div className="name-and-state"> <div className='name-and-state'>
<span className="course-name">{record.courseName}</span> <span className='course-name'>{record.courseName}</span>
{ record.courseType==="LIVE" && {record.courseType === 'LIVE' && <span className='course-state'>{courseStateShow[record.courseState].title}</span>}
<span className="course-state">{courseStateShow[record.courseState].title}</span>
}
</div> </div>
</div> </div>
) );
} },
}, },
{ {
title: '学习进度', title: '学习进度',
key: 'learnFinishPercentage', key: 'learnFinishPercentage',
dataIndex: 'learnFinishPercentage', dataIndex: 'learnFinishPercentage',
width:152,
render: (val, record) => { render: (val, record) => {
return ( return <div className='course-learn-percentage'>{record.learnState === 'FINISH' ? <span>已完成</span> : <span>{val}%</span>}</div>;
<div className="course-learn-percentage"> },
{ record.learnState === "FINISH" ?<span>已完成</span>:<span>{val}%</span>} },
</div>
)
}
}
]; ];
return columns; return columns;
} };
parseChapterColumns = (chapterIndex) => {
const columns = [
{
title: '课节名称',
key: 'chapterName',
dataIndex: 'chapterName',
width: '80%',
},
{
title: '学习进度',
key: 'percentage',
dataIndex: 'percentage',
},
];
return columns;
};
render() { render() {
const {storeCustomerName,storeCustomerPhone,planDataSource,taskDataSource,taskQuery,taskTotalCount} = this.state; const { storeCustomerName, storeCustomerPhone, planDataSource, taskDataSource, taskQuery, taskTotalCount } = this.state;
const { visible } = this.props; const { visible } = this.props;
return ( return (
<Modal <Modal
title="学员学习详情" title='学员学习详情'
onCancel={this.props.onClose} onCancel={this.props.onClose}
onOk={this.props.onClose} onOk={this.props.onClose}
maskClosable={false} maskClosable={false}
visible={visible} visible={visible}
className="user-Learn-modal" className='user-Learn-modal'
closable={true} closable={true}
width={800} width={800}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>} closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}>
> <div className='customer-info'>
<div className="customer-info"> <span className='customer-name'>
<span className="customer-name"> <span>学员:</span>
<span>学员:</span> <span>{storeCustomerName}</span>
<span>{storeCustomerName}</span> </span>
</span> <span className='customer-phone'>
<span className="customer-phone"> <span>手机号:</span>
<span>手机号:</span> <span>{storeCustomerPhone}</span>
<span>{storeCustomerPhone}</span> </span>
</span> </div>
</div> <div className='table-box'>
<div className="plan-instro"> <Table className='plan-table' dataSource={[planDataSource]} columns={this.parsePlanDataColumns()} pagination={false} />
<div className="img-con"> <Table
<img src={planDataSource.coverUrl}/> className='task-table'
</div> rowKey={(record) => record.taskId}
<div> dataSource={taskDataSource}
<div className="plan-name">{planDataSource.planName}</div> columns={this.parseTaskColumns()}
<div className="task-learn-percentage"> pagination={false}
<span>学习进度: {planDataSource.learnFinishPercentage}%</span> expandedRowRender={(record, index) => {
</div> if (!record.courseVOList) {
</div> return;
</div> }
if (record.courseVOList.length !== 0) {
<div> return (
<Table <div>
rowKey={(record) => record.taskId} <Table
className="task-table" showHeader={false}
dataSource={taskDataSource} pagination={false}
columns={this.parseTaskColumns()} dataSource={record.courseVOList}
pagination={false} columns={this.parseCourseColumns(index)}
expandedRowRender={(record,index) => { className='child-table'
if(!record.courseVOList){ expandedRowRender={(chapterRecord, chapterIndex) => {
return if (!chapterRecord.chapterList) {
} return;
if (record.courseVOList.length !== 0 ){ }
return <div> if (chapterRecord.chapterList.length !== 0) {
<Table return (
pagination={false} <div>
dataSource={record.courseVOList} <Table
columns={this.parseCoursecolumns(index)} showHeader={false}
className="child-table" pagination={false}
/> dataSource={chapterRecord.chapterList}
</div> columns={this.parseChapterColumns(chapterIndex)}
} className='chapter-table'
}} />
rowClassName={(record,index)=>{if(index%2===0){return 'odd-row'}else{ return 'even-row'}}} </div>
/> );
</div> }
</Modal> }}
) />
</div>
);
}
}}
rowClassName={(record, index) => {
if (index % 2 === 0) {
return 'odd-row';
} else {
return 'even-row';
}
}}
/>
</div>
</Modal>
);
} }
} }
export default UserLearnDetailModal; export default UserLearnDetailModal;
\ No newline at end of file
.user-Learn-modal{ .user-Learn-modal {
.customer-info {
.customer-info{ margin-bottom: 16px;
margin-bottom:16px; .customer-name {
.customer-name{ font-size: 14px;
font-size:14px; color: #333;
color:#333; margin-right: 32px;
margin-right:32px;
}
.customer-phone{
font-size:14px;
color:#333;
}
}
.plan-instro{
display: flex;
align-items: center;
margin-bottom:16px;
.img-con{
margin-right:8px;
img{
width: 97px;
height: 54px;
display: inline-block;
border-radius:4px;
}
}
.plan-name{
color:#333;
font-size:16px;
}
.plan-learn-percentage{
color:#333;
font-size:14px;
}
} }
.task-table{ .customer-phone {
.ant-table-thead{ font-size: 14px;
tr { color: #333;
th{ }
padding:9px 16px; }
} .plan-instro {
} display: flex;
} align-items: center;
tr{ margin-bottom: 16px;
td{ .img-con {
padding:14px 16px; margin-right: 8px;
} img {
} width: 97px;
.taskName{ height: 54px;
color:#333; display: inline-block;
font-size:14px; border-radius: 4px;
} }
.task-learn-percentage{ }
color:#333; .plan-name {
font-size:14px; color: #333;
font-size: 16px;
}
.plan-learn-percentage {
color: #333;
font-size: 14px;
}
}
.table-box {
.child-table {
margin-left: 40px;
tr > td {
&:first-child {
padding-right: 0 !important;
} }
.course-info{ &:nth-child(2) {
display:flex; padding-left: 0 !important;
margin-left:57px;
align-items: center;
.course-type{
font-size:11px;
color:#666666;
padding:0px 6px;
border: 1px solid #999999;
margin-right:4px;
border-radius: 2px;
line-height: 16px;
}
.name-and-state{
flex:1;
.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;
}
}
} }
.ant-table-expanded-row{ }
td{ .course-info {
padding:0 16px; display: flex;
} .course-type {
border-radius: 2px;
border: 1px solid #999999;
font-size: 11px;
color: #666666;
padding: 1px 8px;
margin-right: 6px;
} }
.ant-table-content{ }
border:1px solid #e8e8e8; }
tr{ .record-name {
td{ display: flex;
border:none; .img-con {
} margin-right: 8px;
.child-table{ img {
width: 97px;
.ant-table-content{ height: 54px;
border:none; border-radius: 4px;
thead{
display:none;
}
tbody tr {
td{
border-bottom:none;
padding:14px 16px;
}
}
}
}
}
.odd-row{
background:transparent;
td{
background: #FFF;
}
& + .ant-table-expanded-row{
background:transparent;
td{
background: #FFF;
}
}
&:hover{
& + .ant-table-expanded-row{
background:transparent;
td{
background: #F3f6fa !important;
}
}
}
}
.even-row{
background:transparent;
td{
background: #FAFAFA;
}
& + .ant-table-expanded-row{
background:transparent;
td{
background: #FAFAFA;
}
}
&:hover{
& + .ant-table-expanded-row{
background:transparent;
td{
background: #F3f6fa !important;
}
}
}
}
} }
}
} }
} }
\ No newline at end of file }
/*
* @Author: yuananting
* @Date: 2021-07-05 10:50:10
* @LastEditors: yuananting
* @LastEditTime: 2021-07-05 11:02:28
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from 'react'; import React from 'react';
import _ from 'underscore'; import _ from 'underscore';
import { Table, Radio, Tabs, Modal, Input, message, Button, Tooltip } from 'antd'; import { Table, Radio, Tabs, Modal, Input, message, Button, Tooltip } from 'antd';
import { PageControl, XMTable } from '@/components'; import { PageControl } from '@/components';
import college from '@/common/lottie/college';
import CourseService from '@/domains/course-domain/CourseService'; import CourseService from '@/domains/course-domain/CourseService';
import User from '@/common/js/user'; import User from '@/common/js/user';
...@@ -79,11 +87,11 @@ class SelectOperatorModal extends React.Component { ...@@ -79,11 +87,11 @@ class SelectOperatorModal extends React.Component {
selectVideo: { selectVideo: {
external: [], external: [],
internal: [], internal: [],
}, //弹窗内已选择的视频课程 }, //弹窗内已选择的线上课程
currentVideoCourseListData: { currentVideoCourseListData: {
external: [], external: [],
internal: [], internal: [],
}, //页面中已关联的视频课程 }, //页面中已关联的线上课程
pictureDataSource: [], pictureDataSource: [],
pictureSize: 10, pictureSize: 10,
...@@ -408,12 +416,13 @@ class SelectOperatorModal extends React.Component { ...@@ -408,12 +416,13 @@ class SelectOperatorModal extends React.Component {
}, },
}, },
{ {
title: '课程时长', title: '课节数',
key: 'courseTime', key: 'courseChapterNum',
dataIndex: 'courseTime', dataIndex: 'courseChapterNum',
width: '20%', width: '20%',
align: 'right',
render: (val, record) => { render: (val, record) => {
return <span className='course-status'>{dealTimeDuration(record.videoDuration)}</span>; return <span>{val || 1}</span>;
}, },
}, },
{ {
...@@ -734,11 +743,7 @@ class SelectOperatorModal extends React.Component { ...@@ -734,11 +743,7 @@ class SelectOperatorModal extends React.Component {
</div> </div>
</div> </div>
<div> <div>
<XMTable <Table
renderEmpty={{
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.liveCourseId} rowKey={(record) => record.liveCourseId}
dataSource={liveDataSource} dataSource={liveDataSource}
columns={this.parseLiveColumns()} columns={this.parseLiveColumns()}
...@@ -829,11 +834,7 @@ class SelectOperatorModal extends React.Component { ...@@ -829,11 +834,7 @@ class SelectOperatorModal extends React.Component {
</div> </div>
</div> </div>
<div> <div>
<XMTable <Table
renderEmpty={{
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.id} rowKey={(record) => record.id}
dataSource={videoDataSource[videoCourseDivision]} dataSource={videoDataSource[videoCourseDivision]}
columns={this.parseVideoColumns()} columns={this.parseVideoColumns()}
...@@ -928,11 +929,7 @@ class SelectOperatorModal extends React.Component { ...@@ -928,11 +929,7 @@ class SelectOperatorModal extends React.Component {
</div> </div>
</div> </div>
<div> <div>
<XMTable <Table
renderEmpty={{
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.id} rowKey={(record) => record.id}
dataSource={pictureDataSource} dataSource={pictureDataSource}
columns={this.parsePictureColumns()} columns={this.parsePictureColumns()}
......
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