Merge branches 'dev_aliyun' and 'dev_video' of https://bdgit.educoder.net/Hjqreturn/educoder into dev_video
	
		
	
				
					
				
			
						commit
						d19043e39a
					
				| @ -0,0 +1,49 @@ | ||||
| import React,{ Component } from "react"; | ||||
| import { Switch , Pagination } from 'antd'; | ||||
| import { NoneData } from 'educoder'; | ||||
| 
 | ||||
| import LiveItem from './LiveItem'; | ||||
| import './video.css'; | ||||
| class Live extends Component{ | ||||
|   | ||||
|    render(){ | ||||
|     const { liveData , lives , successFunc , admin , business , is_teacher , pageSize , changePage } = this.props; | ||||
|     const operation = admin || business || (is_teacher && this.props.checkIfProfessionalCertification()) | ||||
| 
 | ||||
|      return( | ||||
|        <div className="livePanel"> | ||||
|           { | ||||
|             lives && lives.length > 0 ? | ||||
|             <React.Fragment> | ||||
|               <p className="font-grey-9 mt20 mb20 pl5">共 <span className="color-orange">{liveData && liveData.total_count}</span> 个视频</p> | ||||
|               <div className="liveContent"> | ||||
|                 { | ||||
|                   lives.map((item,key)=>{ | ||||
|                     return( | ||||
|                       <LiveItem  | ||||
|                       item={item}  | ||||
|                       {...this.props}  | ||||
|                       {...this.state}  | ||||
|                       successFunc={()=>successFunc()} | ||||
|                       operation={operation} | ||||
|                       ></LiveItem> | ||||
|                     ) | ||||
|                   }) | ||||
|                 } | ||||
|               </div> | ||||
|               { | ||||
|                 liveData && liveData.total_count > pageSize && | ||||
|                 <div className="mt30 mb50 edu-txt-center"> | ||||
|                   <Pagination showQuickJumper total={liveData.total_count} pageSize={pageSize} onChange={(page)=>changePage(page,'live')}></Pagination> | ||||
|                 </div> | ||||
|               } | ||||
|             </React.Fragment> | ||||
|             : | ||||
|             <NoneData style={{width: '100%'}}></NoneData> | ||||
|           }  | ||||
|            | ||||
|        </div> | ||||
|      ) | ||||
|    } | ||||
| } | ||||
| export default Live; | ||||
| @ -0,0 +1,52 @@ | ||||
| import React,{ Component } from "react"; | ||||
| import { Switch } from 'antd'; | ||||
| import { getImageUrl } from 'educoder'; | ||||
| 
 | ||||
| import axios from 'axios'; | ||||
| class LiveItem extends Component{ | ||||
| 
 | ||||
|   changeStatus=(flag,event,id)=>{ | ||||
|     const url = `/live_links/${id}.json`; | ||||
|     axios.put(url,{ | ||||
|       on_status:flag?1:0 | ||||
|     }).then(result=>{ | ||||
|       if(result){ | ||||
|         this.props.showNotification(`直播已${flag?"开启":"关闭"}!`); | ||||
|         const { successFunc } = this.props; | ||||
|         successFunc && successFunc(1); | ||||
|       } | ||||
|     }).catch(error=>{ | ||||
|       console.log(error); | ||||
|     }) | ||||
|   } | ||||
|   render(){ | ||||
|     const { item , operation } = this.props; | ||||
|     return( | ||||
|       <div className="liveItem"> | ||||
|         <div className="lineMiddle livesMain"> | ||||
|           <span className="lineMiddle"> | ||||
|             <img alt={`${item.author_name}`} className="liveAuthor" src={getImageUrl(`images/${item.author_img}`)}/> | ||||
|             <label>{item.author_name}</label> | ||||
|             <span className={item.on_status?"labels living":"labels lived"}>{item.on_status?'已开播':'未开播'}</span> | ||||
|           </span> | ||||
|           { | ||||
|             operation &&  | ||||
|             <Switch checkedChildren="on" unCheckedChildren="off" defaultChecked={item.on_status} onChange={(flag,event)=>this.changeStatus(flag,event,item.id)}></Switch> | ||||
|           } | ||||
|         </div> | ||||
|         <div className="lineMiddle mt15"> | ||||
|           <div className="liveDesc"> | ||||
|             <p><span className="task-hide-2">{item.description}</span></p> | ||||
|           </div> | ||||
|           { | ||||
|             item.on_status? | ||||
|             <a className="btns going" href={`${item.url}`}>进入</a> | ||||
|             : | ||||
|             <span className="btns ect">进入</span> | ||||
|           } | ||||
|         </div> | ||||
|       </div> | ||||
|     ) | ||||
|   } | ||||
| } | ||||
| export default LiveItem; | ||||
| @ -0,0 +1,79 @@ | ||||
| import React,{ Component } from "react"; | ||||
| import { Modal , Form , Input } from 'antd'; | ||||
| 
 | ||||
| import './video.css'; | ||||
| import axios from 'axios'; | ||||
| const { TextArea } = Input; | ||||
| 
 | ||||
| class LiveNew extends Component{ | ||||
|   constructor(props){ | ||||
|     super(props); | ||||
|     this.state={ | ||||
| 
 | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   handleSubmit=()=>{ | ||||
|     this.props.form.validateFields((err, values) => { | ||||
|       if(!err){ | ||||
|         const CourseId=this.props.match.params.coursesId; | ||||
|         const url =  `/courses/${CourseId}/live_links.json`; | ||||
|         axios.post(url,{ | ||||
|           ...values | ||||
|         }).then(result=>{ | ||||
|           if(result){ | ||||
|             this.props.showNotification("添加成功!"); | ||||
|             const { setliveVisibel } = this.props; | ||||
|             setliveVisibel && setliveVisibel(false); | ||||
|           } | ||||
|         }).catch(error=>{ | ||||
|           console.log(error); | ||||
|         }) | ||||
|       } | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   render(){ | ||||
|     const {getFieldDecorator} = this.props.form; | ||||
|     const { visible , setliveVisibel } = this.props; | ||||
|     return( | ||||
|       <Modal | ||||
|         visible={visible} | ||||
|         width="560px" | ||||
|         title={'直播设置'} | ||||
|         footer={null} | ||||
|         closable={false} | ||||
|         className="liveModal" | ||||
|       > | ||||
|         <div className="task-popup-content"> | ||||
|           <Form onSubmit={this.handleSubmit}> | ||||
|             <Form.Item label={`直播链接`}> | ||||
|               {getFieldDecorator('url', { | ||||
|                   rules: [{required: true, message: "请输入第三方直播链接"}], | ||||
|               })( | ||||
|                 <Input placeholder="请输入第三方直播链接,如:腾讯课堂播放链接等。" /> | ||||
|               )} | ||||
|             </Form.Item> | ||||
|             <Form.Item label={`直播说明`} style={{marginBottom:"0px"}}> | ||||
|               {getFieldDecorator('description', { | ||||
|                   rules: [], | ||||
|               })( | ||||
|                 <TextArea rows={4} placeholder="可在此介绍开播具体事项,如开播时间安排等。" /> | ||||
|               )} | ||||
|             </Form.Item> | ||||
|             <p className="flex-middle" style={{justifyContent:"space-between"}}> | ||||
|               <span>EduCoder推荐您使用<a href="https://ke.qq.com/" target="_blank" className="color-blue">腾讯课堂</a>进行直播</span> | ||||
|               <a href="https://pub.idqqimg.com/pc/misc/files/20200204/2e4cb765bef54f0c919c0ab8ab79d969.pdf" target="_blank" className="color-blue">下载操作指引</a> | ||||
|             </p> | ||||
|           </Form> | ||||
|           <div className="clearfix mt30 edu-txt-center"> | ||||
|             <a onClick={()=>setliveVisibel(false)} className="task-btn mr30">取消</a> | ||||
|             <a type="submit" onClick={this.handleSubmit} className="task-btn task-btn-orange">确定</a> | ||||
|           </div> | ||||
|         </div> | ||||
|       </Modal> | ||||
|     ) | ||||
|   } | ||||
| } | ||||
| const WrappedLiveNew = Form.create({name: 'LiveNew'})(LiveNew); | ||||
| export default WrappedLiveNew; | ||||
| @ -0,0 +1,222 @@ | ||||
| import React,{ Component } from "react"; | ||||
| import { Input , Pagination } from 'antd'; | ||||
| import { NoneData ,ActionBtn } from 'educoder'; | ||||
| 
 | ||||
| import VideoUploadList from '../../user/usersInfo/video/VideoUploadList'; | ||||
| import VideoInReviewItem from '../../user/usersInfo/video/VideoInReviewItem'; | ||||
| import HeadlessModal from '../../user/usersInfo/common/HeadlessModal'; | ||||
| import EditVideoModal from '../../user/usersInfo/video/EditVideoModal' | ||||
| import ClipboardJS from 'clipboard' | ||||
| 
 | ||||
| import './video.css'; | ||||
| import '../../user/usersInfo/video/InfosVideo.css' | ||||
| 
 | ||||
| const DEFAULT_VIDEO_WIDTH_IN_MD = "90%" // 400
 | ||||
| const DEFAULT_VIDEO_HEIGHT_IN_MD = "55%" // 400
 | ||||
| 
 | ||||
| const videoEl = null; | ||||
| let _clipboard = null; | ||||
| 
 | ||||
| 
 | ||||
| class Video extends Component{ | ||||
|   constructor(props){ | ||||
|     super(props); | ||||
|     this.state={ | ||||
|       videos:undefined, | ||||
|       count:0, | ||||
|       page:1, | ||||
| 
 | ||||
|       videoId:undefined, | ||||
|       videoVisible:false, | ||||
|       visible:false | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // 编辑的弹框visible
 | ||||
|   setVisible=(flag)=>{ | ||||
|     this.setState({ | ||||
|       visible:flag | ||||
|     }) | ||||
|   } | ||||
| 
 | ||||
|   setVideoVisible=(flag)=>{ | ||||
| 
 | ||||
|     this.setState({ | ||||
|       videoVisible:flag | ||||
|     }) | ||||
|     if (flag === false) { | ||||
|       if (_clipboard) { | ||||
|         this.setState({ | ||||
|           videoId:undefined | ||||
|         }) | ||||
|         _clipboard.listener.destroy(); | ||||
|         _clipboard = null; | ||||
|       } | ||||
|     } else { | ||||
|         // videoEl.current && videoEl.current.play()
 | ||||
| 
 | ||||
|         setTimeout(() => { | ||||
|             if (!_clipboard) { | ||||
|                 _clipboard = new ClipboardJS('.copybtn'); | ||||
|                 _clipboard.on('success', (e) => { | ||||
|                     this.props.showNotification('复制成功'); | ||||
|                 }); | ||||
|             } | ||||
|         }, 200) | ||||
|     } | ||||
|   } | ||||
|    | ||||
| 
 | ||||
|   // 编辑成功后回调的方法
 | ||||
|   editSuccess=()=>{ | ||||
|     const { page } = this.state; | ||||
|     this.props.showNotification("视频名称修改成功!"); | ||||
|     const { listFunc } = this.props; | ||||
|     listFunc && listFunc(page); | ||||
|   } | ||||
| 
 | ||||
|   onEditVideo=(item)=>{ | ||||
|     let videoId = { | ||||
|           videoId: item.id, | ||||
|           title: item.title | ||||
|       } | ||||
|       this.setState({ | ||||
|         videoId, | ||||
|       }) | ||||
|       this.setVisible(true); | ||||
|   } | ||||
| 
 | ||||
|   onMaskClick=(item)=> { | ||||
|     let videoId = { | ||||
|       videoId: item.id, | ||||
|       title: item.title, | ||||
|       file_url: item.file_url, | ||||
|       cover_url: item.cover_url | ||||
|     } | ||||
|     this.setState({ | ||||
|       videoId | ||||
|     }) | ||||
|     this.setVideoVisible(true); | ||||
|   } | ||||
| 
 | ||||
| 
 | ||||
|   setVideoVisible=(flag)=>{ | ||||
| 
 | ||||
|     this.setState({ | ||||
|       videoVisible:flag | ||||
|     }) | ||||
|     if (flag === false) { | ||||
|       if (_clipboard) { | ||||
|         this.setState({ | ||||
|           videoId:undefined | ||||
|         }) | ||||
|         _clipboard.listener.destroy(); | ||||
|         _clipboard = null; | ||||
|       } | ||||
|     } else { | ||||
|         // videoEl.current && videoEl.current.play()
 | ||||
| 
 | ||||
|         setTimeout(() => { | ||||
|             if (!_clipboard) { | ||||
|                 _clipboard = new ClipboardJS('.copybtn'); | ||||
|                 _clipboard.on('success', (e) => { | ||||
|                     this.props.showNotification('复制成功'); | ||||
|                 }); | ||||
|             } | ||||
|         }, 200) | ||||
|     } | ||||
| 
 | ||||
|   } | ||||
| 
 | ||||
|   getCopyText = (file_url, cover_url)=>{ | ||||
|     return `<video src="${file_url}" controls="true" controlslist="nodownload" width="${DEFAULT_VIDEO_WIDTH_IN_MD}" height="${DEFAULT_VIDEO_HEIGHT_IN_MD}" poster="${cover_url}">您的浏览器不支持 video 标签。</video>` | ||||
|   } | ||||
| 
 | ||||
|   render(){ | ||||
|     const { count , visible , videoVisible , videoId } = this.state; | ||||
|     const CourseId=this.props.match.params.coursesId; | ||||
|     const login=this.props.user&&this.props.user.login; | ||||
|     const _inputValue = videoId && this.getCopyText(videoId.file_url, videoId.cover_url); | ||||
| 
 | ||||
|     const { admin , is_teacher ,business} = this.props.user; | ||||
| 
 | ||||
|     const { videos , upload , uploadVideo , videoData , changePage ,pageSize } = this.props; | ||||
| 
 | ||||
|     const operation = admin || business || (is_teacher && this.props.checkIfProfessionalCertification()) | ||||
|     return( | ||||
|       <div> | ||||
|         <EditVideoModal {...this.props} visible={visible} setVisible={this.setVisible} | ||||
|             editSuccess={this.editSuccess} | ||||
|             {...videoId} CourseUser={login} | ||||
|         ></EditVideoModal> | ||||
|         <HeadlessModal | ||||
|             visible={videoVisible} | ||||
|             setVisible={this.setVideoVisible} | ||||
|             className="showVideoModal" | ||||
|             width={800 - 1} | ||||
|           > | ||||
|             { | ||||
|               videoId && | ||||
|               <video | ||||
|                 autoplay="true" | ||||
|                 ref={videoEl} | ||||
|                 src={videoId.file_url} controls="true" controlslist="nodownload"> | ||||
|                 您的浏览器不支持 video 标签。 | ||||
|               </video> | ||||
|             } | ||||
| 
 | ||||
|             <div className="df copyLine"> | ||||
|               <Input value={_inputValue} | ||||
|                   className="dark" | ||||
|               ></Input> | ||||
|               <ActionBtn className="copybtn" data-clipboard-text={_inputValue}>复制视频地址</ActionBtn> | ||||
|             </div> | ||||
|           </HeadlessModal> | ||||
|         <div className="videoPanel"> | ||||
|           { | ||||
|             upload ? | ||||
|             <VideoUploadList {...this.props} flag={true} CourseId={CourseId} CourseUser={login} successFunc={()=>uploadVideo()}></VideoUploadList> | ||||
|             : | ||||
|             <React.Fragment> | ||||
|               { | ||||
|                 videos && videos.length > 0 ? | ||||
|                 <React.Fragment> | ||||
|                   <p className="font-grey-9 mt20 mb20 pl5">共 <span className="color-orange">{videoData && videoData.count}</span> 个视频</p> | ||||
|                   <div className="videoContent"> | ||||
|                   { | ||||
|                     videos.map((item,key)=>{ | ||||
|                       return( | ||||
|                         <VideoInReviewItem | ||||
|                           {...this.props} | ||||
| 
 | ||||
|                           {...item} | ||||
|                           key={item.id} | ||||
|                           onEditVideo={this.onEditVideo} | ||||
|                           onMaskClick={this.onMaskClick} | ||||
|                           getCopyText={this.getCopyText} | ||||
|                           operation={operation} | ||||
|                       > | ||||
|                       </VideoInReviewItem> | ||||
|                       ) | ||||
|                     }) | ||||
|                   } | ||||
|                   </div> | ||||
|                 </React.Fragment> | ||||
|                 : | ||||
|                 <NoneData style={{width: '100%'}}></NoneData> | ||||
|               } | ||||
|                | ||||
|               { | ||||
|                 videoData && videoData.count > pageSize && | ||||
|                 <div className="mt30 mb50 edu-txt-center"> | ||||
|                   <Pagination showQuickJumper total={videoData.count} pageSize={pageSize} onChange={(page)=>changePage(page,'video')}></Pagination> | ||||
|                 </div> | ||||
|               } | ||||
|             </React.Fragment> | ||||
|           } | ||||
|         </div> | ||||
|       </div> | ||||
|     ) | ||||
|   } | ||||
| } | ||||
| export default Video; | ||||
| @ -1,45 +0,0 @@ | ||||
| import React,{ Component } from "react"; | ||||
| import moment from 'moment'; | ||||
| import playIcon from '../../user/usersInfo/video/images/play.png' | ||||
| 
 | ||||
| import { Tooltip } from 'antd'; | ||||
| 
 | ||||
| class VideoItem extends Component{ | ||||
|   render(){ | ||||
|     const { item , onEditVideo} = this.props; | ||||
|     return( | ||||
|       <div> | ||||
|         <img className="cover" src="http://video.educoder.net/5040e61081fe4380ba7bdfd181e44350/snapshots/88d4bf91061149e1ae45fab811ee1a33-00005.jpg" alt="" /> | ||||
|         <div className="playWrap"> | ||||
|           <img className="play mp23" alt="" src={playIcon}></img> | ||||
|         </div> | ||||
|         <div className="videoInfo"> | ||||
|           <div className="title overflowHidden1 font-16" | ||||
|               title={item.title && item.title.length > 20 ? item.title : ''} | ||||
|           >{item.title}</div> | ||||
|           <div className="time"> | ||||
|             {moment(item.published_at || item.created_at).format('YYYY-MM-DD HH:mm:ss')} | ||||
|           </div> | ||||
|           <div className="flex-middle"> | ||||
|             { | ||||
|               item.vv === 0 ? <span></span> : | ||||
|               <Tooltip title="播放次数" placement="bottom" className="color-grey-6"> | ||||
|                 <i className={`icon-dianjiliang iconfont dianjilianicon font-14 fl`}></i> | ||||
|                 <span className="ml8">item.vv</span> | ||||
|               </Tooltip>  | ||||
|             } | ||||
|             <span> | ||||
|               <Tooltip title="编辑" placement="bottom"> | ||||
|                 <a onClick={()=>onEditVideo(item)}><i className={`icon-bianji1 iconfont font-18 color-blue`}></i></a> | ||||
|               </Tooltip> | ||||
|               <Tooltip title="复制链接" placement="bottom"> | ||||
|                 <i className={`icon-fuzhi iconfont font-18 color-blue ml20`}></i> | ||||
|               </Tooltip> | ||||
|             </span> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     ) | ||||
|   } | ||||
| } | ||||
| export default VideoItem; | ||||
					Loading…
					
					
				
		Reference in new issue