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