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