Commit a468e88b by wufan

feat:完成学员观看详情页

parent 7b78f5e2
...@@ -1156,3 +1156,15 @@ window.XMShowClassName = (date, itemName) => { ...@@ -1156,3 +1156,15 @@ window.XMShowClassName = (date, itemName) => {
} }
return 'new-icon' 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
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" ...@@ -10,6 +10,7 @@ import CourseService from "@/domains/course-domain/CourseService"
import RelatedPlanModal from "../../modal/RelatedPlanModal" import RelatedPlanModal from "../../modal/RelatedPlanModal"
import User from "@/common/js/user" import User from "@/common/js/user"
import VideoCourseDetail from '../VideoCourseDetail'; import VideoCourseDetail from '../VideoCourseDetail';
import WatchData from "./WatchData";
import "./VideoCourseList.less" import "./VideoCourseList.less"
...@@ -42,19 +43,11 @@ class VideoCourseList extends React.Component { ...@@ -42,19 +43,11 @@ class VideoCourseList extends React.Component {
} }
// 观看数据弹窗 // 观看数据弹窗
handleShowWatchDataModal = (record) => { handleShowWatchDataModal = (item) => {
const watchDataModal = ( const { match } = this.props;
<WatchDataModal window.RCHistory.push({
type='videoCourseList' pathname: `${match.url}/course-data?type=${item.type}&id=${item.id}`
data={record}
close={() => {
this.setState({
watchDataModal: null
}) })
}}
/>
)
this.setState({ watchDataModal })
} }
// 请求表头 // 请求表头
...@@ -503,6 +496,7 @@ class VideoCourseList extends React.Component { ...@@ -503,6 +496,7 @@ class VideoCourseList extends React.Component {
{this.state.shareLiveModal} {this.state.shareLiveModal}
{this.state.watchDataModal} {this.state.watchDataModal}
<Route path={`${match.url}/video-course-detail`} component={VideoCourseDetail} /> <Route path={`${match.url}/video-course-detail`} component={VideoCourseDetail} />
<Route path={`${match.url}/course-data`} component={WatchData} />
</div> </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 @@ ...@@ -3,7 +3,7 @@
* @Date: 2020-05-19 11:01:31 * @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁 * @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47 * @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗 * @Description 学员观看数据弹窗
*/ */
import React from 'react'; import React from 'react';
import {Table, Modal,Input} from 'antd'; import {Table, Modal,Input} from 'antd';
......
...@@ -452,7 +452,6 @@ class KnowledgeBaseList extends React.Component { ...@@ -452,7 +452,6 @@ class KnowledgeBaseList extends React.Component {
const { match } = this.props; const { match } = this.props;
localStorage.setItem("WatchData_CourseName", item.name); localStorage.setItem("WatchData_CourseName", item.name);
window.RCHistory.push({ 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}` 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