Commit bbd20dcd by zhangleyuan

feat:直播课创建和编辑页处理

parent 55a028ed
......@@ -11,6 +11,7 @@
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
"@types/ali-oss": "^6.0.5",
"@types/qs": "^6.9.5",
"@types/react": "^16.9.46",
"@types/react-dom": "^16.9.8",
......@@ -18,7 +19,6 @@
"@types/underscore": "^1.10.22",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"@types/ali-oss": "^6.0.5",
"ali-oss": "^6.12.0",
"antd": "^4.8.5",
"axios": "^0.20.0",
......
.xm-show-tip {
position: relative;
min-height:32px;
background:#FFF0E7;
background:#FFF4DD;
border-radius:4px;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 12px;
span.icon {
color:#FF8534;
color:#FF9D14;
line-height: 20px;
}
p {
......
@font-face {
font-family: 'iconfont'; /* project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.eot');
src: url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.woff2') format('woff2'),
url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.woff') format('woff'),
url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.ttf') format('truetype'),
url('//at.alicdn.com/t/font_2223403_yeyjxe4w6a.svg#iconfont') format('svg');
src: url('//at.alicdn.com/t/font_2223403_uo63ciaamd.eot');
src: url('//at.alicdn.com/t/font_2223403_uo63ciaamd.eot?#iefix') format('embedded-opentype'),
url('//at.alicdn.com/t/font_2223403_uo63ciaamd.woff2') format('woff2'),
url('//at.alicdn.com/t/font_2223403_uo63ciaamd.woff') format('woff'),
url('//at.alicdn.com/t/font_2223403_uo63ciaamd.ttf') format('truetype'),
url('//at.alicdn.com/t/font_2223403_uo63ciaamd.svg#iconfont') format('svg');
}
.iconfont{
font-family:"iconfont" !important;
......
import React from 'react'
import { Modal, Button } from "antd";
import "./DownloadLiveModal.less"
class DownloadLiveModal extends React.Component {
constructor(props) {
super(props);
this.state = {
image: 'https://image.xiaomaiketang.com/xm/K2sJJHG3pa.png',
tip: '直播上课需要使用客户端,请先下载并安装。',
text: '安装直播客户端',
type: 'pre',
}
}
downloadLiveClient(){
if (type === 'pre') {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
if(isMac){
Modal.info({
title: "抱歉,暂不支持Mac版",
content: "Mac版正在开发中,敬请期待",
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
okText: '我知道了'
});
return;
}
url && window.open(url);
this.setState({
image: 'https://image.xiaomaiketang.com/xm/wPwRdaa7MM.png',
tip: '安装完成后,再次打开即可开始直播。',
text: '我知道了',
type: 'finish',
})
} else {
this.props.onCancel();
}
}
render() {
const { url } = this.props;
const { image, tip, text, type } = this.state;
return <Modal
visible={true}
title="下载客户端"
className="download-live-modal"
footer={null}
onCancel={() => {
this.props.onCancel();
}}
>
<img className="download-image" src={image} alt="" />
<p className="download-tip">{tip}</p>
<Button
type="primary"
className="download-button"
onClick={() => {
}}
>{text}</Button>
</Modal>
}
}
export default DownloadLiveModal;
\ No newline at end of file
.download-live-modal {
.ant-modal-body {
padding: 20px 24px 48px !important;
.download-image {
display: block;
width: 80px;
margin: 0 auto 8px;
}
.download-tip {
color: #666;
text-align: center;
margin-bottom: 32px;
}
.download-button {
display: block;
margin: 0 auto;
}
}
}
\ No newline at end of file
......@@ -177,15 +177,15 @@ class ImgCutModalNew extends React.Component {
}
}
// ImgCutModalNew.propTypes = {
// visible: PropTypes.bool,
// needReUpload: PropTypes.bool, // 是否需要重新上传
// title: PropTypes.string,
// width: PropTypes.number,
// cutWidth: PropTypes.number,
// cutHeight: PropTypes.number,
// imageFile: PropTypes.File
// };
ImgCutModalNew.propTypes = {
visible: PropTypes.bool,
needReUpload: PropTypes.bool, // 是否需要重新上传
title: PropTypes.string,
width: PropTypes.number,
cutWidth: PropTypes.number,
cutHeight: PropTypes.number,
// imageFile: PropTypes.File
};
ImgCutModalNew.defaultProps = {
width: 550,
cutWidth: 502,
......
/**
* 多选日历
* Created by Gentean
* Mail: 4083189@qq.com
* Date: 2016/12/30
* Time: 下午2:32
*/
import React from 'react'
import { message } from "antd";
import moment from 'moment';
require("./MultipleDatePicker.less");
class MultipleDatePicker extends React.Component {
constructor(props) {
super(props);
this.state = {
calendar: "",
calendarDate: props.type ? moment(props.startTime):moment(),
detailList: [],
waitNoticeNumber: 0,
totalCount: 0,
selectDateList: props.selectDateList || [],
endTime: props.endTime || null,
startTime: props.startTime || null,
homeworkProcessEnum: props.homeworkProcessEnum || ''
};
}
componentWillReceiveProps(nextProps) {
this.setState({endTime : nextProps.endTime, startTime: nextProps.startTime, selectDateList: nextProps.selectDateList, homeworkProcessEnum:nextProps.homeworkProcessEnum},() => {
this.handleQuery();
});
}
componentDidMount() {
this.handleQuery();
}
handleQuery() {
var self = this;
self.setState({
calendar: self.renderCalendar(),
});
}
renderCalendar() {
var start = moment(this.state.calendarDate).startOf("month"),
startDay = start.dates(),
// 每月的第一天是星期几 [0-6] 6:日
startWeekOf = start.weekday();
var end = moment(this.state.calendarDate).endOf("month"),
endDay = end.dates(),
endWeekOf = end.weekday();
var dateElms = [];
// 上月余留的天
var prevMonthDays = moment(start).subtract("month", 1).endOf("month"),
prevMonthDaysNumber = prevMonthDays.dates();
for (
var j = prevMonthDaysNumber - startWeekOf + 1, i = 0;
i < startWeekOf;
i++, j++
) {
var time = moment(prevMonthDays).subtract("days", startWeekOf - 1 - i);
dateElms.push(
<li className={"disabled"} key={"before" + i}>
<span>{j}</span>
</li>
);
}
// 本月
for (var i = startDay; i <= endDay; i++) {
var time = moment(start).add("days", i - 1);
var className = "";
if(!this.props.canSelectTodayBefore && time.valueOf() < moment().valueOf() && time.format("YYYY-MM-DD") != moment().format("YYYY-MM-DD")) {
className = 'before-disabled'
}
// 今日待跟进
if (time.format("YYYY-MM-DD") == moment().format("YYYY-MM-DD")) {
className += " today";
}
if (this.state.selectDateList.indexOf(time.valueOf()) > -1) {
className += " active";
const today = moment().startOf('day').valueOf();
if(this.props.type && this.props.type == 'CALENDAR_CLOCK' && (time.valueOf() < today) && this.state.homeworkProcessEnum == 'ONGOING') {
className += " past";
}
}
if(this.state.startTime && this.state.endTime && (time.valueOf() > this.state.endTime.valueOf() || time.valueOf() < this.state.startTime.valueOf())) {
className += " disabled"
}
dateElms.push(
<li
className={className}
key={"curr" + i}
onClick={this.handleShowDetail.bind(this, time, className)}
>
<span>{i}</span>
</li>
);
}
// 下月预来的天
for (var j = 1, i = endWeekOf; i < 6; i++, j++) {
var time = moment(end).add("days", i);
dateElms.push(
<li className={"disabled"} key={"after" + i}>
<span>{j}</span>
</li>
);
}
return dateElms;
}
handleShowDetail(time, className) {
if(!this.props.canSelectTodayBefore && className === 'before-disabled') {
return
}
let date = time.valueOf();
const today = moment().startOf('day').valueOf();
if(this.props.type && this.props.type == 'CALENDAR_CLOCK' && (date < today)) {
return;
}
if(this.state.homeworkProcessEnum == 'ONGOING' && date == today) {
return;
}
if(this.props.type && this.props.type == 'CALENDAR_CLOCK' && this.state.startTime && this.state.endTime && (date > this.state.endTime.valueOf() || date < this.state.startTime.valueOf())) {
return;
}
let tempArr = this.state.selectDateList;
if (tempArr.indexOf(date) > -1) {
let index = tempArr.indexOf(date);
tempArr.splice(index, 1);
} else {
if (tempArr.length > 29 && !this.props.type) {
message.warning("最多选择30天");
return;
} else {
tempArr.push(date);
}
}
this.props.onSelect(tempArr);
this.setState(
{
selectDateList: tempArr,
},
() => {
this.handleQuery();
}
);
}
render() {
const self = this;
const {calendarDate, endTime,startTime } = this.state;
const { type} = this.props;
const prevMonth = startTime && calendarDate.subtract("month", 1).endOf('month').valueOf() < startTime.valueOf();
const nextMonth = !(endTime && calendarDate.add("month", 1).valueOf() < endTime.valueOf());
return (
<div
className={`multiple-calendar ${
type == "CALENDAR_CLOCK" ? "punch-calender" : ""
}`}
>
{type == "CALENDAR_CLOCK" ? (
<div className="punch-control">
<div className="punch-main">
<div
onClick={function () {
if(prevMonth){return}
this.state.calendarDate = this.state.calendarDate.subtract(
"month",
1
);
self.handleQuery();
}.bind(this)}
className={`prev-icon ${prevMonth?'disbled-icon':''}`}
>
<span className="icon iconfont">&#xe65f;</span>
</div>
<span className="month">{this.state.calendarDate.format("YYYY年MM月")}</span>
<div
className={`next-icon ${nextMonth?'disbled-icon':''}`}
onClick={function () {
if(nextMonth){return}
this.state.calendarDate = this.state.calendarDate.add(
"month",
1
);
self.handleQuery();
}.bind(this)}
>
<span className="icon iconfont">&#xe65e;</span>
</div>
</div>
<div
className="self"
onClick={function () {
this.state.calendarDate = moment(startTime);
self.handleQuery();
}.bind(this)}
>
回到起始月
</div>
</div>
) : (
<div className="t-control">
<div
className="prev"
onClick={function () {
this.state.calendarDate = this.state.calendarDate.subtract(
"month",
1
);
self.handleQuery();
}.bind(this)}
>
上月
</div>
<div className="loc">
{this.state.calendarDate.format("YYYY年MM月")}
</div>
<div
className="self"
onClick={function () {
this.state.calendarDate = moment();
self.handleQuery();
}.bind(this)}
>
本月
</div>
<div
className="next"
onClick={function () {
this.state.calendarDate = this.state.calendarDate.add('month', 1);
self.handleQuery()
}.bind(this)}
>
下月
</div>
</div>
)}
<ul className="week">
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
<ul className="calendar" id="multiCalendar">
{this.state.calendar}
</ul>
</div>
);
}
}
MultipleDatePicker.propTypes = {};
MultipleDatePicker.defaultProps = {
reEditUrl: "",
close: function () {},
canSelectTodayBefore: true // 支持选择今天之前的日期
};
export default MultipleDatePicker;
@import '@/core/variables.less';
.multiple-calendar {
width: 295px;
border: 1px solid #e8e8e8;
border-radius: 4px;
ul {
list-style: none;
}
.t-control {
display: flex;
> div {
padding: 2px 0;
text-align: center;
cursor: pointer;
&:hover {
background: #ececec;
}
}
.loc {
flex: 1;
cursor: default;
&:hover {
background: #FFFFFF;
border-radius: 4px;
}
}
.self {
width: 50px;
}
.prev, .next {
width: 50px;
}
}
.week {
font-size: 12px;
li {
display: inline-block;
width: 41px;
text-align: center;
cursor: pointer;
}
}
.calendar {
padding-bottom: 10px;
li {
display: inline-block;
width: 31px;
margin: 0 5px;
text-align: center;
height: 30px;
line-height: 30px;
cursor: pointer;
vertical-align: top;
&:hover {
background: #e8e8e8;
}
&.before-disabled {
color: #e8e8e8;
cursor: default;
&:hover {
background: none!important;
span{
color: #e8e8e8!important;
}
}
}
&.disabled{
color: #e8e8e8;
cursor: default;
&:hover {
background: none!important;
span{
color: #e8e8e8!important;
}
}
}
&.active {
background: @xm-color-primary;
color: #fff;
border-radius: 4px;
}
&.today {
border: 1px solid @xm-color-primary;
border-radius: 5px;
}
}
}
&.punch-calender {
width: 400px;
margin-top: 12px;
.punch-control {
border-bottom: 1px solid rgba(0,0,0,0.06);
position: relative;
.punch-main {
margin: 0 133px;
display: flex;
justify-content: space-between;
align-items: center;
.prev-icon,
.next-icon {
cursor: pointer;
}
.month {
color: #333333;
}
.icon {
color: rgba(0,0,0,0.45);
}
.disbled-icon {
cursor: not-allowed;
.icon {
color: #e8e8e8;
}
}
}
.self {
position: absolute;
right: 8px;
top: 0;
color: #FF7519;
cursor: pointer;
}
}
.week {
li {
width: 56px;
}
}
.calendar li {
width: 56px;
margin: 0 !important;
span {
width: 30px;
height: 30px;
}
&:hover {
background: transparent;
span {
background: transparent;
color: #FF7519;
}
}
&.active {
background: transparent;
color: #fff;
border-radius: none;
span {
background: @xm-color-primary;
border-radius: 4px;
}
&:hover {
span {
color: #fff;
}
}
}
&.today {
border: none;
border-radius: none;
span {
border: 1px solid @xm-color-primary;
border-radius: 5px;
}
}
&.past {
span {
background:rgba(255,133,52,0.1);
border-radius: 4px;
color:rgba(0,0,0,0.25);
}
}
}
}
}
import React from 'react'
import './ShowTips.less'
import {InfoCircleOutlined} from '@ant-design/icons';
function ShowTips(props) {
return (
<div className={`xm-show-tip xm-type-${props.type || 'defulat'}`} >
<span className="icon iconfont">&#xe6f2;</span>
<InfoCircleOutlined className="icon"/>
<p>{props.message}</p>
</div>
)
......
.xm-show-tip {
position: relative;
min-height:32px;
background:#FFF0E7;
background:#FFF4DD;
border-radius:4px;
display: flex;
justify-content: flex-start;
align-items: center;
padding: 0 12px;
span.icon {
color:#FF8534;
line-height: 20px;
.icon {
color:#FF9D14;
line-height: 24px;
height: 20px;
}
p {
color:#666666;
......
......@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-11 17:44:15
* @LastEditTime: 2020-12-12 16:55:50
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
......@@ -25,7 +25,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_yeyjxe4w6a.css">
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_uo63ciaamd.css">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
......
......@@ -79,7 +79,29 @@ class AddLive extends React.Component {
addLiveBasicInfo: {
courseName: null, // 课程名称
coverId: null,
coverUrl: defaultCover
coverUrl: defaultCover,
courseCatalogOption:[
{
value: 'zhejiang',
label: 'Zhejiang',
children: [
{
value: 'hangzhou',
label: 'Hangzhou',
},
],
},
{
value: 'jiangsu',
label: 'Jiangsu',
children: [
{
value: 'nanjing',
label: 'Nanjing',
}
],
},
]
},
// 直播课上课信息
......@@ -632,13 +654,10 @@ class AddLive extends React.Component {
navList={type == "add" ? "新建直播课" : "编辑直播课"}
goBack={this.handleGoBack}
/>
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦助教保有依据国家规定及平台规则进行处理的权利" />
</div>
<div className="add-live-page__form">
<div className="basic-info__wrap">
<div className="title">基本信息</div>
......
.add-live-page {
.box {
margin-bottom: 66px;
margin-bottom: 66px !important;
}
.add-live-page__form {
margin-top: 16px;
......@@ -13,7 +12,7 @@
line-height: 22px;
}
.add-live__class-info {
margin-left: 24px;
margin-left: 14px;
.student {
margin-bottom: 16px;
}
......
......@@ -21,7 +21,7 @@ class LiveCoursePage extends React.Component {
}
}
componentWillMount() {
this.handleFetchLiveList();
this.handleFetchLiveList(this.state.query);
}
// // 获取直播课列表
// handleFetchLiveList = (_query) => {
......@@ -47,7 +47,7 @@ class LiveCoursePage extends React.Component {
// this.setState({ loading: false });
// });
// }
handleFetchLiveList() {
handleFetchLiveList= (_query) => {
const _courseList=[
{
applyMode: "ANYONE",
......
......@@ -7,7 +7,7 @@
*/
import React from 'react';
import { Input, Button, message } from 'antd';
import { Input, Button, message ,Cascader } from 'antd';
import UploadOss from "@/core/upload";
import { ImgCutModalNew } from '@/components';
......@@ -55,11 +55,9 @@ class AddLiveBasic extends React.Component {
render() {
const { showCutModal, imageFile } = this.state;
const { data, liveScene } = this.props;
const { courseName, coverUrl } = data;
const { courseName, coverUrl , courseCatalogOption} = data;
const fileName = '';
// 是否是互动班课,互动班课不显示封面图
const isInteractive = liveScene === 'interactive';
// 当前是否使用的是默认图片
const isDefaultCover = coverUrl === defaultCover;
......@@ -75,46 +73,45 @@ class AddLiveBasic extends React.Component {
onChange={(e) => { this.props.onChange('courseName', e.target.value)}}
/>
</div>
<div className="course-cover">
<span className="label">封面图:</span>
{
!isInteractive &&
<div className="course-cover">
<span className="label">封面图:</span>
<div className="course-cover__wrap">
<div className="img-content">
{
isDefaultCover && <span className="tag">默认图</span>
}
<img src={coverUrl} />
</div>
<div className="opt-btns">
<input
type="file"
value={fileName} // 避免选择同一文件 value不改变 不触发onChange事件
accept="image/png, image/jpeg, image/bmp, image/jpg"
ref="stagePicInputFile"
style={{display: 'none'}}
onChange={(event) => { this.handleShowImgCutModal(event) }}
/>
<Button onClick={() => {
this.setState({
currentInputFile: this.refs.stagePicInputFile
});
this.refs.stagePicInputFile.click();
}}>上传图片</Button>
<span
className={`default-btn ${isDefaultCover ? 'disabled' : ''}`}
onClick={this.handleResetCoverUrl}
>使用默认图</span>
<div className="tips">建议尺寸690*398像素,图片支持jpg、jpeg、png格式。</div>
</div>
<div className="course-cover__wrap">
<div className="img-content">
{
isDefaultCover && <span className="tag">默认图</span>
}
<img src={coverUrl} />
</div>
<div className="opt-btns">
<input
type="file"
value={fileName} // 避免选择同一文件 value不改变 不触发onChange事件
accept="image/png, image/jpeg, image/bmp, image/jpg"
ref="stagePicInputFile"
style={{display: 'none'}}
onChange={(event) => { this.handleShowImgCutModal(event) }}
/>
<Button onClick={() => {
this.setState({
currentInputFile: this.refs.stagePicInputFile
});
this.refs.stagePicInputFile.click();
}}>上传图片</Button>
<span
className={`default-btn ${isDefaultCover ? 'disabled' : ''}`}
onClick={this.handleResetCoverUrl}
>使用默认图</span>
<div className="tips">建议尺寸690*398像素,图片支持jpg、jpeg、png格式。</div>
</div>
</div>
}
</div>
<div className="course-catalog">
<span className="label"><span className="require">*</span>课程分类:</span>
<Cascader options={courseCatalogOption} style={{ width: 240 }} placeholder="请选择课程分类" />
</div>
<ImgCutModalNew
title="裁剪"
width={550}
......
......@@ -2,7 +2,7 @@
.label {
width: 100px;
text-align: right;
display:inline-block;
.require {
color: #EC4B35;
}
......@@ -69,6 +69,9 @@
color: #999;
}
}
.course-catalog{
margin:20px 0 0 14px;
}
}
#imgCutModalNew {
......
......@@ -63,7 +63,7 @@
.label {
width: 100px;
text-align: right;
display:inline-block;
.require {
color: #EC4B35;
}
......@@ -154,7 +154,6 @@
}
}
.teacher,
.student,
.deduction-student,
.no-deduction-student {
......@@ -191,6 +190,9 @@
}
}
}
.tip-icon{
color:#BFBFBF;
}
}
.iconfont {
......
......@@ -69,6 +69,7 @@ class AddLiveIntro extends React.Component {
// this.setState({ diskList });
// });
}
// 删除简介
handleDeleteIntro = (index) => {
const { liveCourseMediaRequests } = this.props.data;
......@@ -208,85 +209,52 @@ class AddLiveIntro extends React.Component {
render() {
const { liveScene, liveType, isXiaomai, isEdit, data: { introduction, needRecord, whetherRecord, liveCourseMediaRequests = [], liveCourseWarmMedia = {}, isAutoSendReport } } = this.props;
const { showCutModal, warmUrl, showSelectFileModal, diskList, imageFile } = this.state
// 是否是互动班课
const isInteractive = liveScene === 'interactive';
return (
<div className="add-live__intro-info">
{(liveScene === 'large' || (liveScene === 'interactive' && liveType === 'LARGE_CLASS_LIVE')) && isXiaomai &&
<div className="playback">
<span className="label">直播回放:</span>
<div className="content">
<Radio.Group disabled={liveScene === 'large' && !isEdit} value={needRecord} onChange={(e) => { this.props.onChange('needRecord', e.target.value) }}>
<Row style={{ marginBottom: '5px' }}>
<Col span={8}>
<Radio value="YES">
自动录制
</Radio>
</Col>
<Col span={16}>
<span className="playback__text">系统自助进行全程直播录制</span>
</Col>
</Row>
<Row>
<Col span={8}>
<Radio value="NO">
手动录制
</Radio>
</Col>
<Col span={16}>
<span className="playback__text">老师手动选择何时开始录制</span>
</Col>
</Row>
</Radio.Group>
</div>
</div>
}
{
(liveScene === 'interactive' && liveType !== 'LARGE_CLASS_LIVE' && isXiaomai) &&
<div className="interactive-playback">
<span className="label">直播回放:</span>
<div className="content">
<Radio.Group disabled={liveScene === 'large' && !isEdit} value={whetherRecord} onChange={(e) => { this.props.onChange('whetherRecord', e.target.value) }}>
<Radio value="YES">
自动录制
</Radio>
<Radio value="NO">
不录制
</Radio>
<div className="playback">
<span className="label">直播回放:</span>
<div className="content">
<Radio.Group>
<Row style={{ marginBottom: '5px' }}>
<Col span={8}>
<Radio value="YES">
自动录制
</Radio>
</Col>
<Col span={16}>
<span className="playback__text">系统自助进行全程直播录制</span>
</Col>
</Row>
<Row>
<Col span={8}>
<Radio value="NO">
手动录制
</Radio>
</Col>
<Col span={16}>
<span className="playback__text">讲师手动选择何时开始录制</span>
</Col>
</Row>
</Radio.Group>
<Popover content={
<div className="record-rule-wrap">
<p>录制费 = 录课单价 x 回放视频时长</p>
<ul>
<li>录课单价:2元/小时</li>
<li>回放视频时长:0.5小时起收,不足0.5小时的按0.5小时结算</li>
</ul>
<p className="text">示例:生成了49分26秒的回放视频,不足1小时按1小时计算,录制费就是2元</p>
</div>
}>
<span className="check-record-rule">查看录制费规则</span>
</Popover>
</div>
</div>
}
{
((liveScene === 'large' || liveScene === 'interactive') && isXiaomai && window.currentUserInstInfo.saaSVersionEnum === 'V_50') &&
<div className="auto-send-class-report">
<span className="label">自动发送报告:</span>
<Switch
checked={isAutoSendReport}
onChange={(checked) => this.props.onChange("isAutoSendReport",checked)}></Switch>
<div className="open-text">开启:课程结束后,公众号将自动发送课堂报告给上课学员(仅已绑定微信号的学员)</div>
<div className="close-text">关闭:不自动发送,但学员仍可通过课次详情页查看课堂报告</div>
</div>
<div className="allow-tourist-join">
<span className="label">允许游客加入:</span>
<div className="content">
<Row>
<Col span={3}>
<Switch />
</Col>
<Col span={21}>
<div>开启:用户可直接进入直播间观看直播</div>
<div>关闭:用户需先填写手机号并短信验证,通过后才可进入直播间观看直播</div>
</Col>
</Row>
</div>
}
{ ((liveScene === 'large' || liveScene === 'interactive') && isXiaomai) &&
<div className="warmup">
</div>
<div className="warmup">
<span className="label">直播暖场图:</span>
<div className="course-cover__wrap">
<div className="img-content" style={ liveCourseWarmMedia.mediaUrl ? {background: '#000'} : {} }>
<img src={liveCourseWarmMedia.mediaType === 'VIDEO' ? `${liveCourseWarmMedia.mediaUrl}?x-oss-process=video/snapshot,t_0,m_fast` : (liveCourseWarmMedia.mediaUrl ? liveCourseWarmMedia.mediaUrl : defaultCover )} />
{
......@@ -297,7 +265,6 @@ class AddLiveIntro extends React.Component {
}}/>
</div>
}
</div>
<div className="opt-btns">
<Button
......@@ -323,24 +290,11 @@ class AddLiveIntro extends React.Component {
</div>
</div>
}
<div className="introduce">
<span className="label">直播简介:</span>
<div className="content">
{
isInteractive &&
<TextArea
value={introduction}
placeholder="简单介绍下这次课吧"
maxLength={200}
style={{ width: 480 }}
onChange={(e) => { this.props.onChange('introduction', e.target.value) }}
/>
}
{
!isInteractive &&
[
<div className="intro-list">
{
liveCourseMediaRequests.map((item, index) => {
......@@ -370,10 +324,10 @@ class AddLiveIntro extends React.Component {
}
})
}
</div>,
</div>
<div className="operate">
<div className="operate__item" onClick={this.handleAddIntroText}>
<span className="icon iconfont">&#xe760;</span>
<span className="icon iconfont">&#xe639;</span>
<span className="text">文字</span>
</div>
......@@ -386,16 +340,15 @@ class AddLiveIntro extends React.Component {
}}
>
<div className="operate__item">
<span className="icon iconfont">&#xe74a;</span>
<span className="icon iconfont">&#xe63b;</span>
<span className="text">图片</span>
</div>
</Upload>
</div>,
</div>
<div className="tips">
• 图片支持jpeg、jpg、png、gif格式
</div>
]
}
</div>
</div>
{/* 选择暖场图文件弹窗 */}
......
......@@ -13,7 +13,9 @@
display: flex;
flex-direction: row;
}
.allow-tourist-join{
display:flex;
}
.radio {
display: block;
height: 30px;
......
......@@ -13,7 +13,8 @@ import { Table, Modal, Tooltip, Badge, message, Dropdown, Button,Switch} from 'a
// import User from "@/core/user";
// import User_t from "@/teacher/core/user";
import { PageControl } from "@/components";
// import DownloadLiveModal from '@/components/DownloadLiveModal';
// import { LIVE_SHARE_MAP } from '@/common/constants/academic/cloudClass';
import DownloadLiveModal from '@/components/DownloadLiveModal';
// import LiveStudentListModal from '../modal/LiveStudentListModal';
// import CheckBalanceModal from '../modal/CheckBalanceModal';
......@@ -56,6 +57,8 @@ class LiveCourseList extends React.Component {
super(props);
this.state = {
columns: [],
openDownloadModal:false,
url:''
}
}
componentWillMount(){
......@@ -110,7 +113,6 @@ class LiveCourseList extends React.Component {
// TODOLIST 确定后端是否是根据liveCourseId 返回数据
window.RCHistory.push(`/live-course-data?type=large&id=${item.liveCourseId}`)
}
parseColumns = () => {
const menu = (item) => (
<div className="live-course-more-menu">
......@@ -208,6 +210,7 @@ class LiveCourseList extends React.Component {
<div
key="enter_live_room1"
className="operate__item"
onClick={() => { this.handleEnterLiveRoom(item) }}
>进入直播间
</div>
<span className="operate__item split" key="enter_live_room1_split"> | </span>
......@@ -280,11 +283,55 @@ class LiveCourseList extends React.Component {
// pathname: '/create-live-course?type=edit',
// })
}
refreshCourseList = ()=>{
this.props.onChange(this.props.query);
}
//进入直播间
handleEnterLiveRoom = (item) => {
if (item.startTime - Date.now() > 1800000) {
Modal.warning({
title: "你来得太早了",
okText: '我知道了',
content: "请于开始上课前30分钟来直播上课。",
icon: (
<span
className="icon iconfont default-confirm-icon"
style={{ color: "#FFBB54 !important" }}
>
&#xe6f1;
</span>
),
});
} else {
// axios
// .Apollo("public/businessLive/getCourseDetail", {
// liveCourseId: item.liveCourseId,
// })
// .then((res) => {
// const url = `xiaomai5://instId=${instId}&courseId=${item.liveCourseId}&teacherId=${item.teacherId}&uid=${ teacherId ? User_t.uid() : User.uid()}&aid=${teacherId ? "" : User.aid()}&tid=${teacherId || ""}&identity=${identity}&classType=${item.liveType}&xmVersion=${window.NewVersion ? '5.0' : '4.0'}`;
// if (res.result.courseState === "FINISH") {
// Modal.warning({
// title: "刷新页面",
// icon: <QuestionCircleOutlined />,
// content: "课次已结束,请刷新一下",
// onOk: () => {
// this.refreshCourseList();
// }
// });
// } else {
this.setState({ url:'', openDownloadModal: true });
// }
// });
}
}
render() {
const { total, query, courseList, loading} = this.props;
const { current, size } = query;
const { columns} = this.state;
const { openDownloadModal,
downloadUrl, url, columns,
} = this.state;
return (
<div className="live-course-list">
<Table
......@@ -309,6 +356,18 @@ class LiveCourseList extends React.Component {
/>
</div>
{ this.state.shareLiveModal }
{openDownloadModal && (
<DownloadLiveModal
url={downloadUrl}
onCancel={() => {
this.setState({
url: '',
openDownloadModal:
false });
}}
/>
)}
<iframe src={url} style={{ display: "none" }} />
</div>
)
}
......
......@@ -18,6 +18,29 @@ class LiveCourseOpt extends React.Component {
pathname: '/create-live-course?type=add',
})
}
// 下载直播客户端
handleDownloadClient = () => {
const isMac = /macintosh|mac os x/i.test(navigator.userAgent);
// 判断用户系统
if(!isMac) {
// axios
// .Apollo("anon/version/getLastedVersion", { model: 1, platform: 1 })
// .then((res) => {
// const a = document.createElement("a");
// document.body.appendChild(a);
// a.href = res.result.releaseUrl;
// a.click();
// document.body.removeChild(a);
// })
}else {
Modal.info({
title: "抱歉,暂不支持Mac版",
content: "Mac版正在开发中,敬请期待",
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
okText: '我知道了'
});
}
}
render() {
return (
<div className="live-course-opt">
......
......@@ -2,7 +2,7 @@
* @Author: zhangleyuan
* @Date: 2020-11-27 15:06:31
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-09 11:23:52
* @LastEditTime: 2020-12-12 14:49:13
* @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
......
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