Commit a468e88b by wufan

feat:完成学员观看详情页

parent 7b78f5e2
......@@ -1156,3 +1156,15 @@ window.XMShowClassName = (date, itemName) => {
}
return 'new-icon'
}
// 格式化时间段为时分
window.formatDuration = function (time) {
const diff = Math.floor(time % 3600);
let hours = Math.floor(time / 3600);
let mins = Math.floor(diff / 60);
let seconds = Math.floor(time % 60);
hours = hours < 10 ? ("0" + hours) : hours;
mins = mins < 10 ? ("0" + mins) : mins;
seconds = seconds < 10 ? ("0" + seconds) : seconds;
return hours + ":" + mins + ":" + seconds;
};
\ No newline at end of file
......@@ -7,173 +7,273 @@
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import React from 'react'
import { Modal } from 'antd'
import moment from 'moment'
import './PreviewCourseModal.less'
import React from "react";
import { Modal, Tabs } from "antd";
import moment from "moment";
import ChapterList from "../video-course/components/ChapterList";
import "./PreviewCourseModal.less";
const { TabPane } = Tabs;
const courseStateShow = {
UN_START: {
title: '待开课'
title: "待开课",
},
STARTING: {
title: '上课中'
title: "上课中",
},
FINISH: {
title: '已完成'
title: "已完成",
},
EXPIRED: {
code: 4,
title: '未成功开课',
color: '#CCCCCC'
}
}
title: "未成功开课",
color: "#CCCCCC",
},
};
class PreviewCourseModal extends React.Component {
constructor(props) {
super(props)
this.state = {}
super(props);
this.state = {
activeTab: "courseChapter",
};
}
dealTimeDuration = (time) => {
const diff = Math.floor(time % 3600)
let hours = Math.floor(time / 3600)
let mins = Math.floor(diff / 60)
let seconds = Math.floor(time % 60)
hours = hours < 10 ? '0' + hours : hours
mins = mins < 10 ? '0' + mins : mins
seconds = seconds < 10 ? '0' + seconds : seconds
return hours + ':' + mins + ':' + seconds
}
const diff = Math.floor(time % 3600);
let hours = Math.floor(time / 3600);
let mins = Math.floor(diff / 60);
let seconds = Math.floor(time % 60);
hours = hours < 10 ? "0" + hours : hours;
mins = mins < 10 ? "0" + mins : mins;
seconds = seconds < 10 ? "0" + seconds : seconds;
return hours + ":" + mins + ":" + seconds;
};
dealWithTime = (startTime, endTime) => {
const startDate = new Date(Number(startTime))
const endDate = new Date(Number(endTime))
const startDate = new Date(Number(startTime));
const endDate = new Date(Number(endTime));
const year = startDate.getFullYear()
const month = startDate.getMonth() + 1 < 10 ? `0${startDate.getMonth() + 1}` : startDate.getMonth() + 1
const day = startDate.getDate() < 10 ? `0${startDate.getDate()}` : startDate.getDate()
const year = startDate.getFullYear();
const month =
startDate.getMonth() + 1 < 10
? `0${startDate.getMonth() + 1}`
: startDate.getMonth() + 1;
const day =
startDate.getDate() < 10
? `0${startDate.getDate()}`
: startDate.getDate();
const startHour = startDate.getHours() < 10 ? `0${startDate.getHours()}` : startDate.getHours()
const startMinute = startDate.getMinutes() < 10 ? `0${startDate.getMinutes()}` : startDate.getMinutes()
const startHour =
startDate.getHours() < 10
? `0${startDate.getHours()}`
: startDate.getHours();
const startMinute =
startDate.getMinutes() < 10
? `0${startDate.getMinutes()}`
: startDate.getMinutes();
const endHour = endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours()
const endMinute = endDate.getMinutes() < 10 ? `0${endDate.getMinutes()}` : endDate.getMinutes()
const endHour =
endDate.getHours() < 10 ? `0${endDate.getHours()}` : endDate.getHours();
const endMinute =
endDate.getMinutes() < 10
? `0${endDate.getMinutes()}`
: endDate.getMinutes();
const liveDateStr = `${year}-${month}-${day}`
const startTimeStr = `${startHour}:${startMinute}`
const endTimeStr = `${endHour}:${endMinute}`
const liveDateStr = `${year}-${month}-${day}`;
const startTimeStr = `${startHour}:${startMinute}`;
const endTimeStr = `${endHour}:${endMinute}`;
return {
liveDateStr,
startTimeStr,
endTimeStr
}
}
endTimeStr,
};
};
render() {
const { courseBasicInfo, courseClassInfo = {}, courseIntroInfo, type, courseState, origin } = this.props
const { coverUrl, courseName, scheduleVideoUrl, videoDuration } = courseBasicInfo
const { liveDate, calendarTime, startTime, endTime, timeHorizonStart, timeHorizonEnd, teacherName } = courseClassInfo
const { introduce } = courseIntroInfo
let liveDateStr, startTimeStr, endTimeStr
if (type === 'add') {
const _liveDate = moment(calendarTime[0]).format('YYYY-MM-DD')
console.log('_liveDate', _liveDate)
const _timeHorizonStart = moment(startTime).format('HH:mm')
const _timeHorizonEnd = moment(endTime).format('HH:mm')
const _startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x')
const _endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x')
const { liveDateStr: _liveDateStr, startTimeStr: _startTimeStr, endTimeStr: _endTimeStr } = this.dealWithTime(_startTime, _endTime)
liveDateStr = _liveDateStr
startTimeStr = _startTimeStr
endTimeStr = _endTimeStr
const {
courseBasicInfo,
courseClassInfo = {},
courseIntroInfo,
type,
courseState,
courseChapterList = [],
} = this.props;
const { coverUrl, courseName, scheduleVideoUrl, videoDuration } =
courseBasicInfo;
const {
liveDate,
calendarTime,
startTime,
endTime,
timeHorizonStart,
timeHorizonEnd,
teacherName,
} = courseClassInfo;
const { introduce } = courseIntroInfo;
let { activeTab } = this.state;
let liveDateStr, startTimeStr, endTimeStr;
if (type === "add") {
const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD");
console.log("_liveDate", _liveDate);
const _timeHorizonStart = moment(startTime).format("HH:mm");
const _timeHorizonEnd = moment(endTime).format("HH:mm");
const _startTime = moment(_liveDate + " " + _timeHorizonStart).format(
"x"
);
const _endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x");
const {
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr,
endTimeStr: _endTimeStr,
} = this.dealWithTime(_startTime, _endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
} else {
const _liveDate = moment(liveDate).format('YYYY-MM-DD')
const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm')
const _timeHorizonEnd = moment(timeHorizonEnd).format('HH:mm')
const startTime = moment(_liveDate + ' ' + _timeHorizonStart).format('x')
const endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x')
const { liveDateStr: _liveDateStr, startTimeStr: _startTimeStr, endTimeStr: _endTimeStr } = this.dealWithTime(startTime, endTime)
liveDateStr = _liveDateStr
startTimeStr = _startTimeStr
endTimeStr = _endTimeStr
const _liveDate = moment(liveDate).format("YYYY-MM-DD");
const _timeHorizonStart = moment(timeHorizonStart).format("HH:mm");
const _timeHorizonEnd = moment(timeHorizonEnd).format("HH:mm");
const startTime = moment(_liveDate + " " + _timeHorizonStart).format("x");
const endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x");
const {
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr,
endTimeStr: _endTimeStr,
} = this.dealWithTime(startTime, endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
}
return (
<Modal
title='预览'
title="预览"
visible={true}
width={680}
onCancel={this.props.close}
footer={null}
maskClosable={false}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
className='preview-live-course-modal'>
<div className='container__wrap'>
<div className='container'>
<div className='container__header'>
{type === 'videoCourse' ? (
closeIcon={
<span className="icon iconfont modal-close-icon">&#xe6ef;</span>
}
className="preview-live-course-modal"
>
<div className="container__wrap">
<div className="container">
<div className="container__header">
{type === "videoCourse" ? (
<video
controls
src={scheduleVideoUrl}
poster={coverUrl ? coverUrl : `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`}
className='course-url'
src={courseChapterList.length && courseChapterList[0].mediaUrl || scheduleVideoUrl }
poster={
coverUrl
? coverUrl
: "https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png"
}
className="course-url"
/>
) : (
<img src={coverUrl} className='course-cover' />
<img src={coverUrl} className="course-cover" />
)}
</div>
{type === 'videoCourse' ? (
<div className='container__body'>
<div className='title__name'>{courseName}</div>
{videoDuration && <div>视频时长:{this.dealTimeDuration(videoDuration)}</div>}
{type === "videoCourse" ? (
<div className="container__body">
<div className="title__name">{courseName}</div>
{videoDuration && (
<div>视频时长:{this.dealTimeDuration(videoDuration)}</div>
)}
</div>
) : (
<div className='container__body'>
<div className='container__body__title'>
<div className='title__name'>{courseName}</div>
<div className='title__state'>{courseStateShow[courseState].title}</div>
<div className="container__body">
<div className="container__body__title">
<div className="title__name">{courseName}</div>
<div className="title__state">
{courseStateShow[courseState].title}
</div>
</div>
<div className='container__body__time'>
<span className='time__label'>上课时间:</span>
<span className='time__value'>
<div className="container__body__time">
<span className="time__label">上课时间:</span>
<span className="time__value">
{[
<span>{liveDateStr}&nbsp;</span>,
<span>
{startTimeStr}~{endTimeStr}
</span>
</span>,
]}
</span>
</div>
<div className='container__body__teacher'>
<span className='teacher__label'>上课老师:</span>
<span className='teacher__value'>{teacherName}</span>
<div className="container__body__teacher">
<span className="teacher__label">上课老师:</span>
<span className="teacher__value">{teacherName}</span>
</div>
</div>
)}
<div className='container__introduction'>
{type === 'videoCourse' ? (
<div className='container__introduction__title'>线上课简介</div>
) : (
<div className='container__introduction__title'>直播课简介</div>
<div className="container__introduction">
<Choose>
<When condition={type === "videoCourse"}>
<Tabs
activeKey={activeTab}
onChange={(key) => {
this.setState({
activeTab: key,
});
}}
>
<TabPane tab="课程目录" key="courseChapter"></TabPane>
<TabPane tab="课程简介" key="courseIntro"></TabPane>
</Tabs>
</When>
<Otherwise>
<div className="container__introduction__title">
直播课简介
</div>
</Otherwise>
</Choose>
<Choose>
<When condition={type === "videoCourse"}>
{activeTab === "courseChapter" && (
<div className="container__chapter">
{
<ChapterList
chapterType="VIDEO"
courseChapterList={courseChapterList}
/>
}
</div>
)}
{activeTab === "courseIntro" && (
<div className="container__introduction__list editor-box">
<div
className="intro-item text"
dangerouslySetInnerHTML={{
__html: introduce,
}}
/>
</div>
)}
<div className='container__introduction__list editor-box'>
</When>
<Otherwise>
<div className="container__introduction__list editor-box">
<div
className='intro-item text'
className="intro-item text"
dangerouslySetInnerHTML={{
__html: introduce
__html: introduce,
}}
/>
</div>
</Otherwise>
</Choose>
</div>
</div>
</div>
</Modal>
)
);
}
}
export default PreviewCourseModal
export default PreviewCourseModal;
import React from 'react';
import './ChapterList.less';
function ChapterList(props){
const { courseChapterList } = props;
return <div className='chapter-list-component'>
<If condition={courseChapterList.length > 0}>
{
_.map(courseChapterList,(item,index) => {
return <div className='course-ware'>
<div className='course-ware__index'>{`0${index + 1 } `}</div>
<div className="course-ware__detail">
<div className='course-ware__detail__name'>{item.mediaName}</div>
<div className='course-ware__detail__duration'>{window.formatDuration(item.videoDuration)}</div>
</div>
</div>
})
}
</If>
</div>
}
export default ChapterList;
\ No newline at end of file
.chapter-list-component {
.course-ware {
display: flex;
padding: 10px 0;
border-bottom: 1px dashed #EEEEEE;
&:last-child {
border-bottom: none;
}
&__index {
width: 18px;
height: 18px;
font-size: 13px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #999999;
line-height: 18px;
}
&__detail {
display: flex;
flex-direction: column;
width: calc(~'100% - 18px');
&__name {
width: 267px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 21px;
margin-bottom: 4px;
}
&__duration {
color: #999999;
}
}
}
}
\ No newline at end of file
......@@ -10,6 +10,7 @@ import CourseService from "@/domains/course-domain/CourseService"
import RelatedPlanModal from "../../modal/RelatedPlanModal"
import User from "@/common/js/user"
import VideoCourseDetail from '../VideoCourseDetail';
import WatchData from "./WatchData";
import "./VideoCourseList.less"
......@@ -42,19 +43,11 @@ class VideoCourseList extends React.Component {
}
// 观看数据弹窗
handleShowWatchDataModal = (record) => {
const watchDataModal = (
<WatchDataModal
type='videoCourseList'
data={record}
close={() => {
this.setState({
watchDataModal: null
handleShowWatchDataModal = (item) => {
const { match } = this.props;
window.RCHistory.push({
pathname: `${match.url}/course-data?type=${item.type}&id=${item.id}`
})
}}
/>
)
this.setState({ watchDataModal })
}
// 请求表头
......@@ -503,6 +496,7 @@ class VideoCourseList extends React.Component {
{this.state.shareLiveModal}
{this.state.watchDataModal}
<Route path={`${match.url}/video-course-detail`} component={VideoCourseDetail} />
<Route path={`${match.url}/course-data`} component={WatchData} />
</div>
)
}
......
import User from "@/common/js/user";
import college from "@/common/lottie/college";
import { PageControl, XMTable } from "@/components";
import Breadcrumbs from "@/components/Breadcrumbs";
import CourseService from "@/domains/course-domain/CourseService";
import { Input } from 'antd';
import React from "react";
import { withRouter } from "react-router-dom";
const { Search } = Input;
class WatchData extends React.Component {
constructor(props) {
super(props);
const id = window.getParameterByName("id");
this.state = {
id,
visible: true,
dataSource: [],
query: {
current: 1,
size: 10,
},
totalCount: 0,
};
}
componentDidMount() {
this.handleFetchDataList();
}
// 获取观看视频数据列表
handleFetchDataList = () => {
const { query, id } = this.state;
const params = {
...query,
courseId: id,
storeId: User.getStoreId(),
};
CourseService.videoWatchInfo(params).then((res) => {
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
});
};
parseColumns = () => {
const columns = [
{
title: '观看学员',
key: 'name',
dataIndex: 'name'
},
{
title: '手机号',
key: 'phone',
dataIndex: 'phone'
},
{
title: '首次观看时间',
key: 'firstWatch',
dataIndex: 'firstWatch',
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
}
},
{
title: '学习进度',
key: 'progress',
dataIndex: 'progress',
render: (val) => {
return <span>{val}</span>
}
},
{
title: "操作",
key: "operate",
dataIndex: "operate",
width: 210,
render: (val, record) => {
return (
<div className="operate">
<div
className="operate__item"
// onClick={() => this.handleShowShareModal(record)}
>
学习详情
</div>
</div>
);
},
},
];
return columns;
};
render() {
const { dataSource, totalCount, query } = this.state;
const { current, size } = query;
return (
<div className="page data-list">
<Breadcrumbs
navList="观看学员数据"
goBack={() => {
window.RCHistory.goBack();
}}
/>
<div className="box-header">
<div className="course-title"></div>
<div className="filter-box">
<Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
</div>
</div>
<div className="box">
<XMTable
renderEmpty={{
image: college,
description: "暂无数据",
}}
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
scroll={{ x: 1500 }}
bordered
className="video-list-table"
/>
</div>
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={totalCount}
toPage={(page) => {
const _query = {...query, current: page + 1};
this.setState({
query:_query
},()=>{ this.handleFetchDataList()})
}}
/>
</div>
</div>
);
}
}
export default withRouter(WatchData);
......@@ -3,7 +3,7 @@
* @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗
* @Description 学员观看数据弹窗
*/
import React from 'react';
import {Table, Modal,Input} from 'antd';
......
......@@ -452,7 +452,6 @@ class KnowledgeBaseList extends React.Component {
const { match } = this.props;
localStorage.setItem("WatchData_CourseName", item.name);
window.RCHistory.push({
// pathname: `${match.url}/course-data?type=${item.courseType}&id=${item.liveCourseId}`,
pathname: `${match.url}/course-data?type=${item.type}&id=${item.id}`
})
}
......
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