Commit 973e9412 by wufan

Merge branch 'hotfix/pangguoming/20210629/modify_course_manage_default_img' into 'master'

Hotfix/pangguoming/20210629/modify course manage default img

See merge request !57
parents 2c1b9ce7 8968c2d0
......@@ -12,7 +12,6 @@ npm-shrinkwrap.json
.DS_Store
.AppleDouble
.LSOverride
yarn.lock
yarn-error.lock
# IntelliJ project files
......@@ -57,7 +56,6 @@ npm-debug.log
*.zip
build/vendor.js.map
package-lock.json
.vscode/*
demo.js
debug.log
This source diff could not be displayed because it is too large. You can view the blob instead.
import User from '@/common/js/user';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import CourseService from '@/domains/course-domain/CourseService';
import { Button, message } from 'antd';
import React from 'react';
import { withRouter } from "react-router-dom";
import { Table, Button, Modal, message } from 'antd';
import { withRouter } from 'react-router-dom';
import dealTimeDuration from '../utils/dealTimeDuration';
import { PageControl } from "@/components";
import './DataList.less';
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user';
const liveTypeMap = {
USER: "普通用户",
ANCHOR: "讲师",
ADMIN: "管理员(助教)",
GUEST: "游客"
USER: '普通用户',
ANCHOR: '讲师',
ADMIN: '管理员(助教)',
GUEST: '游客',
};
class PlaybackData extends React.Component {
constructor(props) {
super(props);
const courseId = getParameterByName("id"); // 课程ID
const courseId = getParameterByName('id'); // 课程ID
this.state = {
playbackData: [],
......@@ -24,8 +25,8 @@ class PlaybackData extends React.Component {
size: 10,
total: 0,
liveCourseId: courseId,
storeId: User.getStoreId()
}
storeId: User.getStoreId(),
};
}
componentDidMount() {
......@@ -33,12 +34,12 @@ class PlaybackData extends React.Component {
}
fetchPlaybackList = (page = 1) => {
const { size, liveCourseId } = this.state
const { size, liveCourseId } = this.state;
const params = {
liveCourseId,
current: page,
size
}
size,
};
CourseService.fetchPlaybackList(params).then((res) => {
if (res.result) {
......@@ -47,38 +48,35 @@ class PlaybackData extends React.Component {
playbackData: records,
current,
size,
total
total,
});
}
});
};
getPlaybackColumns() {
const columns = [
{
title: "观看学员",
dataIndex: "userName",
title: '观看学员',
dataIndex: 'userName',
},
{
title: "手机号",
dataIndex: "phone"
title: '手机号',
dataIndex: 'phone',
},
{
title: "观看者类型",
dataIndex: "userRole",
title: '观看者类型',
dataIndex: 'userRole',
render: (text) => <span>{liveTypeMap[text]}</span>,
},
{
title: "开始观看时间",
dataIndex: "entryTime",
render: (text) => (
<span>{text ? formatDate("YYYY-MM-DD H:i", parseInt(text)) : '-'}</span>
),
title: '开始观看时间',
dataIndex: 'entryTime',
render: (text) => <span>{text ? formatDate('YYYY-MM-DD H:i', parseInt(text)) : '-'}</span>,
},
{
title: "观看时长",
dataIndex: "lookingDuration",
title: '观看时长',
dataIndex: 'lookingDuration',
render: (text) => {
return <span>{text ? dealTimeDuration(text) : '-'}</span>;
},
......@@ -92,65 +90,67 @@ class PlaybackData extends React.Component {
CourseService.exportPlayBackCourseData({
liveCourseId,
exportLiveType: "PLAY_BACK",
storeId
exportLiveType: 'PLAY_BACK',
storeId,
}).then((res) => {
const link = res.result;
this.setState({
link
link,
});
document.getElementById("load-play-back-excel").click();
document.getElementById('load-play-back-excel').click();
if(res.success){
message.success("导出成功!")
if (res.success) {
message.success('导出成功!');
}
})
});
}
onShowSizeChange = (current, size) => {
if (current == size) {
return;
}
this.setState({ size }, this.fetchUserData)
}
this.setState({ size }, this.fetchUserData);
};
render() {
const { playbackData, total, current, size, link} = this.state
const { playbackData, total, current, size, link } = this.state;
return (
<div>
<a
href={link}
target="_blank"
download
id="load-play-back-excel"
style={{ position: "absolute", left: "-10000px" }}
>
<a href={link} target='_blank' download id='load-play-back-excel' style={{ position: 'absolute', left: '-10000px' }}>
111
</a>
<Button onClick={() => {this.handleplaybackExport()}}>导出</Button>
<Table
<Button
onClick={() => {
this.handleplaybackExport();
}}>
导出
</Button>
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
bordered
size="small"
size='small'
columns={this.getPlaybackColumns()}
dataSource={playbackData}
pagination={false}
style={{ margin: '16px 0' }}>
</Table>
{ total > 0 &&
<PageControl
size="small"
current={current - 1}
pageSize={size}
total={total}
onShowSizeChange={this.onShowSizeChange}
toPage={(page) => {
this.fetchPlaybackList(page + 1);
}}
/>
}
style={{ margin: '16px 0' }}></XMTable>
{total > 0 && (
<PageControl
size='small'
current={current - 1}
pageSize={size}
total={total}
onShowSizeChange={this.onShowSizeChange}
toPage={(page) => {
this.fetchPlaybackList(page + 1);
}}
/>
)}
</div>
)
);
}
}
export default withRouter(PlaybackData);
\ No newline at end of file
export default withRouter(PlaybackData);
......@@ -6,24 +6,23 @@
* @Description: 大班直播、互动班课的直播课列表
*/
import User from '@/common/js/user';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import DownloadLiveModal from '@/components/DownloadLiveModal';
import BaseService from '@/domains/basic-domain/baseService';
import { appId, LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
import React from 'react';
import { Table, Modal, message, Dropdown, Switch, Tooltip } from 'antd';
import { Route, withRouter } from 'react-router-dom';
import { PageControl } from '@/components';
import DownloadLiveModal from '@/components/DownloadLiveModal';
import _ from 'underscore';
import DataList from '../DataList/DataList';
import ManageCoursewareModal from '../modal/ManageCoursewareModal';
import ShareLiveModal from '../modal/ShareLiveModal';
import RelatedPlanModal from '../modal/RelatedPlanModal';
import ShareLiveModal from '../modal/ShareLiveModal';
import './LiveCourseList.less';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { appId, LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService';
import BaseService from '@/domains/basic-domain/baseService';
import DataList from '../DataList/DataList';
import User from '@/common/js/user';
import _ from 'underscore';
const { confirm } = Modal;
const courseStateShow = {
......@@ -785,7 +784,11 @@ class LiveCourseList extends React.Component {
return (
<div className='live-course-list'>
<Table
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
bordered
size='middle'
pagination={false}
......
/*
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Last Modified by: chenshu
* @Last Modified time: 2021-03-24 15:13:38
* @Description 余额异常弹窗
*/
import React from 'react';
import {Table, Modal,Input} from 'antd';
import { PageControl } from "@/components";
import Service from "@/common/js/service";
import User from '@/common/js/user'
import { Modal, Input } from 'antd';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import Service from '@/common/js/service';
import User from '@/common/js/user';
import './WatchDataModal.less';
import dealTimeDuration from "../../utils/dealTimeDuration";
import dealTimeDuration from '../../utils/dealTimeDuration';
const { Search } = Input;
class WatchDataModal extends React.Component {
constructor(props) {
super(props);
this.state = {
visible:true,
dataSource:[],
size:10,
visible: true,
dataSource: [],
size: 10,
query: {
current: 1,
},
totalCount:0
totalCount: 0,
};
}
componentDidMount() {
this.handleFetchDataList();
}
onClose = () =>{
onClose = () => {
this.props.close();
}
};
// 获取观看视频数据列表
// 获取观看视频数据列表
handleFetchDataList = () => {
const {query,size,totalCount} = this.state
const { query, size, totalCount } = this.state;
const { id } = this.props.data;
const params ={
const params = {
...query,
size,
courseId:id,
storeId:User.getStoreId()
}
courseId: id,
storeId: User.getStoreId(),
};
Service.Hades('public/hades/mediaCourseWatchInfo', params).then((res) => {
const { result = {} } = res ;
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total)
totalCount: Number(total),
});
});
}
handleChangNickname = (value)=>{
};
handleChangNickname = (value) => {
const isPhone = (value || '').match(/^\d+$/);
const { query } = this.state;
if(isPhone){
const { query } = this.state;
if (isPhone) {
query.phone = value;
query.nickName = null;
}else{
} else {
query.nickName = value;
query.phone = null;
}
query.current = 1;
this.setState({
query
})
}
query,
});
};
onShowSizeChange = (current, size) => {
if (current == size) {
return
return;
}
this.setState({
size
},()=>{this.handleFetchDataList()})
}
this.setState(
{
size,
},
() => {
this.handleFetchDataList();
}
);
};
// 请求表头
parseColumns = () => {
......@@ -86,92 +92,110 @@ class WatchDataModal extends React.Component {
{
title: '观看学员',
key: 'name',
dataIndex: 'name'
dataIndex: 'name',
},
{
title: '手机号',
key: 'phone',
dataIndex: 'phone'
dataIndex: 'phone',
},
{
title: '观看者类型',
key: 'userRole',
dataIndex: 'userRole'
dataIndex: 'userRole',
},
{
title: '首次观看时间',
key: 'firstWatch',
dataIndex: 'firstWatch',
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
}
return formatDate('YYYY-MM-DD H:i', val);
},
},
{
title: '观看总时长',
key: 'watchDuration',
dataIndex: 'watchDuration',
render: (val) => {
return <span>{val ? dealTimeDuration(val) : "00:00:00" }</span>
}
return <span>{val ? dealTimeDuration(val) : '00:00:00'}</span>;
},
},
{
title: '学习进度',
key: 'progress',
dataIndex: 'progress',
render: (val) => {
return <span>{val === 100 ? '已完成' : `${val || 0}%`}</span>
}
}
return <span>{val === 100 ? '已完成' : `${val || 0}%`}</span>;
},
},
];
return columns;
}
};
render() {
const { visible,size,dataSource,totalCount,query} = this.state;
const { visible, size, dataSource, totalCount, query } = this.state;
return (
<Modal
title="图文课观看数据"
visible={visible}
footer={null}
onCancel={this.onClose}
maskClosable={false}
className="watch-data-modal"
closable={true}
width={800}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
>
<div className="search-container">
<Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
</div>
<div>
<Table
rowKey={record => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
/>
{dataSource.length >0 &&
<div className="box-footer">
<PageControl
current={query.current - 1}
pageSize={size}
total={totalCount}
size="small"
toPage={(page) => {
const _query = {...query, current: page + 1};
this.setState({
query:_query
},()=>{ this.handleFetchDataList()})
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
}
</div>
</Modal>
)
<Modal
title='图文课观看数据'
visible={visible}
footer={null}
onCancel={this.onClose}
maskClosable={false}
className='watch-data-modal'
closable={true}
width={800}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}>
<div className='search-container'>
<Search
placeholder='搜索学员姓名/手机号'
style={{ width: 200 }}
onChange={(e) => {
this.handleChangNickname(e.target.value);
}}
onSearch={() => {
this.handleFetchDataList();
}}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
/>
</div>
<div>
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
/>
{dataSource.length > 0 && (
<div className='box-footer'>
<PageControl
current={query.current - 1}
pageSize={size}
total={totalCount}
size='small'
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.setState(
{
query: _query,
},
() => {
this.handleFetchDataList();
}
);
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
)}
</div>
</Modal>
);
}
}
export default WatchDataModal;
\ No newline at end of file
export default WatchDataModal;
import college from '@/common/lottie/college';
import { XMTable } from '@/components';
import { Modal } from 'antd';
import React from 'react';
import { Modal, Table } from "antd";
import ChargeArgeement from "./ChargeArgeement";
import "./AccountChargeModal.less";
class AccountChargeRecords extends React.Component{
import './AccountChargeModal.less';
import ChargeArgeement from './ChargeArgeement';
class AccountChargeRecords extends React.Component {
constructor(props) {
super(props);
this.state = {
......@@ -15,14 +17,12 @@ class AccountChargeRecords extends React.Component{
getList = () => {
const { instId } = window.currentUserInstInfo;
axios
.Business("public/liveAssets/rechargeProtocol", { instId })
.then((res) => {
const list = res.result;
this.setState({
list,
});
axios.Business('public/liveAssets/rechargeProtocol', { instId }).then((res) => {
const list = res.result;
this.setState({
list,
});
});
};
handleProtcol = (id) => {
const agreement = (
......@@ -42,29 +42,28 @@ class AccountChargeRecords extends React.Component{
render() {
const columns = [
{
title: "签订人",
dataIndex: "operatorName",
width: 140
title: '签订人',
dataIndex: 'operatorName',
width: 140,
},
{ title: "关联订单ID", dataIndex: "orderId" },
{ title: '关联订单ID', dataIndex: 'orderId' },
{
title: "签订时间",
dataIndex: "createTime",
title: '签订时间',
dataIndex: 'createTime',
render: (text, record) => {
return <span>{formatDate("YYYY-MM-DD H:i", parseInt(text))}</span>;
return <span>{formatDate('YYYY-MM-DD H:i', parseInt(text))}</span>;
},
},
{
title: "签订协议",
dataIndex: "operate",
title: '签订协议',
dataIndex: 'operate',
render: (text, record) => {
return (
<div
style={{ cursor: "pointer", color: "#FC9C6B" }}
style={{ cursor: 'pointer', color: '#FC9C6B' }}
onClick={() => {
this.handleProtcol(record.protocolId);
}}
>
}}>
《服务协议》
</div>
);
......@@ -74,29 +73,31 @@ class AccountChargeRecords extends React.Component{
const { list } = this.state;
return (
<Modal
title="服务协议签订记录"
title='服务协议签订记录'
visible={true}
width={680}
footer={null}
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
onCancel={() => {
this.props.close();
}}
>
}}>
<div>
<div
style={{
fontSize: "14px",
color: "#666666",
lineHeight: "20px",
fontSize: '14px',
color: '#666666',
lineHeight: '20px',
marginBottom: 16,
}}
>
}}>
以下是本校区自助充值时签订协议的记录
</div>
<Table
size="middle"
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
size='middle'
columns={columns}
dataSource={list}
pagination={false}
......
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import { Modal, Tooltip } from 'antd';
import React from 'react';
import { Modal, Table, Tooltip } from "antd";
import { ShowTips, PageControl } from "@/components";
import "./AccountChargeModal.less";
import './AccountChargeModal.less';
class ChargingDetailModal extends React.Component {
constructor(props) {
......@@ -25,22 +26,20 @@ class ChargingDetailModal extends React.Component {
handleToPage = (page = 1) => {
const params = _.clone(this.state.query);
params.current = page;
axios
.Apollo("public/businessLive/queryStudentVisitData", params)
.then((res) => {
if (res.result) {
const { records = [], total } = res.result;
this.setState({
list: records,
totalCount: total,
query: params,
});
}
});
axios.Apollo('public/businessLive/queryStudentVisitData', params).then((res) => {
if (res.result) {
const { records = [], total } = res.result;
this.setState({
list: records,
totalCount: total,
query: params,
});
}
});
};
getTeacherData = () => {
window.axios
.Apollo("public/businessLive/queryTeacherVisitData", {
.Apollo('public/businessLive/queryTeacherVisitData', {
liveCourseId: this.props.liveCourseId,
})
.then((res) => {
......@@ -57,27 +56,27 @@ class ChargingDetailModal extends React.Component {
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;
hours = hours < 10 ? '0' + hours : hours;
mins = mins < 10 ? '0' + mins : mins;
seconds = seconds < 10 ? '0' + seconds : seconds;
return hours + ':' + mins + ':' + seconds;
};
getColumns = (type) => {
const columns = [
{
title: type == "student" ? "学生姓名" : "老师姓名",
dataIndex: "userName",
title: type == 'student' ? '学生姓名' : '老师姓名',
dataIndex: 'userName',
},
{
title: "手机号",
dataIndex: "phone",
title: '手机号',
dataIndex: 'phone',
render: (text, record) => {
return <p>{text}</p>;
},
},
{
title: "累计在线时长",
dataIndex: "totalDuration",
title: '累计在线时长',
dataIndex: 'totalDuration',
render: (text, record) => {
return <span>{text ? this.dealTimeDuration(text) : '-'}</span>;
},
......@@ -86,14 +85,14 @@ class ChargingDetailModal extends React.Component {
title: (
<span>
是否计费&nbsp;
<Tooltip title="仅对累计在线时长≥10分钟的老师或学员计费">
<span className="icon iconfont">&#xe6f2;</span>
<Tooltip title='仅对累计在线时长≥10分钟的老师或学员计费'>
<span className='icon iconfont'>&#xe6f2;</span>
</Tooltip>
</span>
),
dataIndex: "type",
dataIndex: 'type',
render: (text, record) => {
return <span>{record.totalDuration > 600 ? "计费" : "不计费"}</span>; //大于十分钟的计费
return <span>{record.totalDuration > 600 ? '计费' : '不计费'}</span>; //大于十分钟的计费
},
},
];
......@@ -103,38 +102,45 @@ class ChargingDetailModal extends React.Component {
const { list, query, totalCount, teacherList } = this.state;
return (
<Modal
title="计费人数详情"
title='计费人数详情'
visible={true}
width={680}
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
className="charging-detail-modal"
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
className='charging-detail-modal'
footer={null}
onCancel={() => {
this.props.close();
}}
>
}}>
<div>
<div style={{ marginBottom: 16 }}>
<div className="detail-title">老师详情</div>
<Table
size="middle"
columns={this.getColumns("teacher")}
<div className='detail-title'>老师详情</div>
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
size='middle'
columns={this.getColumns('teacher')}
dataSource={teacherList}
pagination={false}
bordered
/>
</div>
<div className="detail-title">学生详情</div>
<Table
size="middle"
columns={this.getColumns("student")}
<div className='detail-title'>学生详情</div>
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
size='middle'
columns={this.getColumns('student')}
dataSource={list}
pagination={false}
bordered
/>
<PageControl
size="small"
size='small'
current={query.current - 1}
pageSize={query.size}
total={totalCount}
......
......@@ -6,21 +6,19 @@
* @LastEditTime: 2021-02-01 14:00:36
*/
import React, { useState, useEffect } from "react";
import { Modal, Table, Button, message } from "antd";
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import Bus from '@/core/bus';
import { PageControl } from "@/components";
import hasExportPermission from '../utils/hasExportPermission';
import { Button, message, Modal } from 'antd';
import React from 'react';
import dealTimeDuration from '../utils/dealTimeDuration';
import "./ClassRecordModal.less";
import hasExportPermission from '../utils/hasExportPermission';
import './ClassRecordModal.less';
const liveTypeMap = {
USER: "学生",
ANCHOR: "老师",
ADMIN: "助教",
USER: '学生',
ANCHOR: '老师',
ADMIN: '助教',
};
class PlayBackRecordModal extends React.Component {
......@@ -38,7 +36,7 @@ class PlayBackRecordModal extends React.Component {
totalWatchNum: 0,
};
}
componentDidMount() {
this.fetchPlayBackList();
}
......@@ -46,22 +44,20 @@ class PlayBackRecordModal extends React.Component {
fetchPlayBackList = (page = 1) => {
const params = _.clone(this.state.query);
params.current = page;
window.axios
.Apollo("public/businessLive/queryUserReplayRecordPage", params)
.then((res) => {
const { records = [], total } = res.result;
this.setState({
query: params,
total,
playBackList: records,
});
window.axios.Apollo('public/businessLive/queryUserReplayRecordPage', params).then((res) => {
const { records = [], total } = res.result;
this.setState({
query: params,
total,
playBackList: records,
});
});
};
fetchAllStatistics = () => {
const { liveCourseId } = this.props.liveItem;
window.axios
.Apollo("public/businessLive/queryReplayStatistics", {
.Apollo('public/businessLive/queryReplayStatistics', {
liveCourseId,
})
.then((res) => {
......@@ -80,7 +76,7 @@ class PlayBackRecordModal extends React.Component {
const hours = Math.floor(time / 3600);
const mins = Math.floor(diff / 60);
const seconds = Math.floor(time % 60);
return hours + "小时" + mins + "分";
return hours + '小时' + mins + '分';
};
// 导出
......@@ -88,126 +84,128 @@ class PlayBackRecordModal extends React.Component {
const { liveItem, type } = this.props;
const { liveCourseId } = liveItem;
const url = !type ? 'api-b/b/lesson/exportLargeClassLiveAsync' : 'api-b/b/lesson/exportClassInteractionLiveSync';
window.axios.post(url, {
liveCourseId,
exportLiveType: 0
}).then((res) => {
Bus.trigger('get_download_count');
Modal.success({
title: '导出任务提交成功',
content: '请前往右上角的“导出中心”进行下载',
okText: '我知道了',
window.axios
.post(url, {
liveCourseId,
exportLiveType: 0,
})
.then((res) => {
Bus.trigger('get_download_count');
Modal.success({
title: '导出任务提交成功',
content: '请前往右上角的“导出中心”进行下载',
okText: '我知道了',
});
});
});
}
};
handleExportV5 = () => {
const { liveItem, type } = this.props;
const { liveCourseId } = liveItem;
const url = !type ? 'public/businessLive/exportLargeClassLiveAsync' : 'public/businessLive/exportClassInteractionLiveSync';
window.axios.Apollo(url, {
liveCourseId,
exportLiveType: 'PLAY_BACK'
}).then((res) => {
Bus.trigger('get_download_count');
Modal.success({
title: '导出任务提交成功',
content: '请前往右上角的“任务中心”进行下载',
okText: '我知道了',
window.axios
.Apollo(url, {
liveCourseId,
exportLiveType: 'PLAY_BACK',
})
.then((res) => {
Bus.trigger('get_download_count');
Modal.success({
title: '导出任务提交成功',
content: '请前往右上角的“任务中心”进行下载',
okText: '我知道了',
});
});
});
}
};
render() {
const columns = [
{
title: "观看者姓名",
dataIndex: "userName",
title: '观看者姓名',
dataIndex: 'userName',
},
{
title: "观看者手机号",
dataIndex: "phone",
title: '观看者手机号',
dataIndex: 'phone',
render: (text, record) => {
return (
<p>
{!(
(!window.NewVersion && !window.currentUserInstInfo.teacherId) ||
(window.NewVersion && Permission.hasEduStudentPhone())
)
? (text || "").replace(/(\d{3})(\d{4})(\d{4})/, "$1****$3")
{!((!window.NewVersion && !window.currentUserInstInfo.teacherId) || (window.NewVersion && Permission.hasEduStudentPhone()))
? (text || '').replace(/(\d{3})(\d{4})(\d{4})/, '$1****$3')
: text}
</p>
);
},
},
{
title: "观看者类型",
dataIndex: "liveRole",
key: "liveRole",
title: '观看者类型',
dataIndex: 'liveRole',
key: 'liveRole',
render: (text) => <span>{liveTypeMap[text]}</span>,
},
{
title: "开始观看时间",
dataIndex: "entryTime",
key: "entryTime",
render: (text) => (
<span>{text ? formatDate("YYYY-MM-DD H:i", parseInt(text)) : '-'}</span>
),
title: '开始观看时间',
dataIndex: 'entryTime',
key: 'entryTime',
render: (text) => <span>{text ? formatDate('YYYY-MM-DD H:i', parseInt(text)) : '-'}</span>,
},
{
title: "观看时长",
dataIndex: "lookingDuration",
key: "lookingDuration",
title: '观看时长',
dataIndex: 'lookingDuration',
key: 'lookingDuration',
render: (text) => {
return <span>{text ? dealTimeDuration(text) : '-'}</span>;
},
},
];
const {
query,
total,
playBackList,
totalWatchNum,
recordDuration,
} = this.state;
const { query, total, playBackList, totalWatchNum, recordDuration } = this.state;
const { type } = this.props;
return (
<Modal
title="回放记录"
className="play-back-modal"
title='回放记录'
className='play-back-modal'
width={680}
visible={true}
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}
footer={null}
onCancel={() => {
this.props.close();
}}
>
{
hasExportPermission(type) &&
<Button onClick={_.debounce(() => {
if (!playBackList.length) {
message.warning('暂无数据可导出');
return;
}
if (window.NewVersion) {
this.handleExportV5();
} else {
this.handleExport();
}
}, 500, true)}>导出</Button>
}
<Table
size="small"
}}>
{hasExportPermission(type) && (
<Button
onClick={_.debounce(
() => {
if (!playBackList.length) {
message.warning('暂无数据可导出');
return;
}
if (window.NewVersion) {
this.handleExportV5();
} else {
this.handleExport();
}
},
500,
true
)}>
导出
</Button>
)}
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
size='small'
columns={columns}
dataSource={playBackList}
pagination={false}
className="table-no-scrollbar"
className='table-no-scrollbar'
/>
<PageControl
size="small"
size='small'
current={query.current - 1}
pageSize={query.size}
total={total}
......
/*
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗
*/
import User from '@/common/js/user';
import { PageControl, XMTable } from '@/components';
import CourseService from '@/domains/course-domain/CourseService';
import { Input, Modal } from 'antd';
import college from '@/common/lottie/college';
import React from 'react';
import {Table, Modal,Input} from 'antd';
import { PageControl } from "@/components";
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'
import dealTimeDuration from '../../utils/dealTimeDuration';
import './WatchDataModal.less';
import dealTimeDuration from "../../utils/dealTimeDuration";
const { Search } = Input;
class WatchDataModal extends React.Component {
constructor(props) {
super(props);
this.state = {
visible:true,
dataSource:[],
size:10,
visible: true,
dataSource: [],
size: 10,
query: {
current: 1,
},
totalCount:0
totalCount: 0,
};
}
componentDidMount() {
this.handleFetchDataList();
}
onClose = () =>{
onClose = () => {
this.props.close();
}
};
// 获取观看视频数据列表
// 获取观看视频数据列表
handleFetchDataList = () => {
const {query,size,totalCount} = this.state
const { query, size, totalCount } = this.state;
const { id } = this.props.data;
const params ={
const params = {
...query,
size,
courseId:id,
storeId:User.getStoreId()
}
courseId: id,
storeId: User.getStoreId(),
};
CourseService.videoWatchInfo(params).then((res) => {
const { result = {} } = res ;
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total)
totalCount: Number(total),
});
});
}
handleChangNickname = (value)=>{
};
handleChangNickname = (value) => {
const isPhone = (value || '').match(/^\d+$/);
const { query } = this.state;
if(isPhone){
const { query } = this.state;
if (isPhone) {
query.phone = value;
query.nickName = null;
}else{
} else {
query.nickName = value;
query.phone = null;
}
query.current = 1;
this.setState({
query
})
}
query,
});
};
onShowSizeChange = (current, size) => {
if (current == size) {
return
return;
}
this.setState({
size
},()=>{this.handleFetchDataList()})
}
this.setState(
{
size,
},
() => {
this.handleFetchDataList();
}
);
};
// 请求表头
parseColumns = () => {
......@@ -86,84 +92,102 @@ class WatchDataModal extends React.Component {
{
title: '观看学员',
key: 'name',
dataIndex: 'name'
dataIndex: 'name',
},
{
title: '手机号',
key: 'phone',
dataIndex: 'phone'
dataIndex: 'phone',
},
{
title: '观看者类型',
key: 'userRole',
dataIndex: 'userRole'
dataIndex: 'userRole',
},
{
title: '首次观看时间',
key: 'firstWatch',
dataIndex: 'firstWatch',
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val)
}
return formatDate('YYYY-MM-DD H:i', val);
},
},
{
title: '观看时长',
key: 'watchDuration',
dataIndex: 'watchDuration',
render: (val) => {
return <span>{val ? dealTimeDuration(val) : "00:00:00" }</span>
}
}
return <span>{val ? dealTimeDuration(val) : '00:00:00'}</span>;
},
},
];
return columns;
}
};
render() {
const { visible,size,dataSource,totalCount,query} = this.state;
const { visible, size, dataSource, totalCount, query } = this.state;
return (
<Modal
title="视频课观看数据"
visible={visible}
footer={null}
onCancel={this.onClose}
maskClosable={false}
className="watch-data-modal"
closable={true}
width={800}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
>
<div className="search-container">
<Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
</div>
<div>
<Table
rowKey={record => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
/>
{dataSource.length >0 &&
<div className="box-footer">
<PageControl
current={query.current - 1}
pageSize={size}
total={totalCount}
size="small"
toPage={(page) => {
const _query = {...query, current: page + 1};
this.setState({
query:_query
},()=>{ this.handleFetchDataList()})
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
}
</div>
</Modal>
)
<Modal
title='视频课观看数据'
visible={visible}
footer={null}
onCancel={this.onClose}
maskClosable={false}
className='watch-data-modal'
closable={true}
width={800}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}>
<div className='search-container'>
<Search
placeholder='搜索学员姓名/手机号'
style={{ width: 200 }}
onChange={(e) => {
this.handleChangNickname(e.target.value);
}}
onSearch={() => {
this.handleFetchDataList();
}}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
/>
</div>
<div>
<XMTable
renderEmpty={{
image: college,
description: '暂无数据',
}}
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
/>
{dataSource.length > 0 && (
<div className='box-footer'>
<PageControl
current={query.current - 1}
pageSize={size}
total={totalCount}
size='small'
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.setState(
{
query: _query,
},
() => {
this.handleFetchDataList();
}
);
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
)}
</div>
</Modal>
);
}
}
export default WatchDataModal;
\ No newline at end of file
export default WatchDataModal;
@import '../../core/variables.less';
@top-height: 0px;
@menu-bakg: #FFF;
@active-color: #2966FF;
@menu-bakg: #fff;
@active-color: #2966ff;
.left-container {
position: absolute;
z-index: 2;
......@@ -24,20 +24,23 @@
margin: 15px 0 15px 8px;
}
}
.menu-type-icon{
.menu-type-icon {
margin: 8px 14px 0px 4px;
cursor: pointer;
.icon{
font-size:14px;
color:#5E606A;
.icon {
font-size: 14px;
color: #5e606a;
}
}
}
.ant-menu {
padding-left: 0 !important;
color: #333;
background: #FFF !important;
background: #fff !important;
.ant-menu-title-content {
margin-left: 0 !important;
}
}
.left {
-webkit-user-select: none;
......@@ -48,7 +51,7 @@
display: -webkit-flex;
flex-direction: column;
-webkit-flex-direction: column;
.nav {
-webkit-flex: 1;
cursor: default;
......@@ -59,78 +62,88 @@
display: none;
}
.icon {
margin-right: 20px
margin-right: 20px;
}
.icon-img-box {
// display: flex;
display: inline-block;
width: 40px;
height: 40px;
.icon-img {
margin-left: 12px;
}
margin-right: 0 !important;
}
.icon-img-title {
margin-left: 0 !important;
}
.icon-img{
width:18px;
height:18px;
margin-right:6px;
.icon-img {
width: 18px;
height: 18px;
}
.listType {
width: 5px;
height: 5px;
background: #9A9DA7;
background: #9a9da7;
border-radius: 50%;
top: 18px;
left: 38px;
position: absolute;
}
.ant-menu-item{
padding-left: 13px !important;
.ant-menu-item {
padding-left: 0 !important;
padding-right: 0px;
margin: 6px 8px;
width: calc(100% - 15px);
&:hover{
background: #F3F6FA;
&:hover {
background: #f3f6fa;
border-radius: 2px;
color:#333;
color: #333;
}
}
.ant-menu-item-selected{
background-color:@active-color;
color:#FFF;
border-radius:2px;
&:hover{
color:#FFF;
.ant-menu-item-selected {
background-color: @active-color;
color: #fff;
border-radius: 2px;
&:hover {
color: #fff;
}
}
.ant-menu-submenu{
.ant-menu-submenu-title{
margin:6px 8px;
padding-left:13px !important;
.ant-menu-submenu {
.ant-menu-submenu-title {
margin: 6px 8px;
padding-left: 0 !important;
}
.ant-menu-item{
padding-left:46px !important;
.ant-menu-item {
padding-left: 46px !important;
}
}
.ant-menu-submenu-selected{
color:@active-color;
.ant-menu-item-selected{
color:#FFF;
.ant-menu-submenu-selected {
color: @active-color;
.ant-menu-item-selected {
color: #fff;
.listType {
background: @active-color;
}
}
}
.ant-menu-submenu-arrow{
right:22px;
color:#5E606A;
.ant-menu-submenu-arrow {
right: 22px;
color: #5e606a;
}
}
}
&.left-container-vertical {
width: 56px;
.menu-type-icon{
margin:4px 0 0px 22px;
.menu-type-icon {
margin: 4px 0 0px 22px;
}
.left {
.ant-menu-submenu-arrow{
display:none !important;
.ant-menu-submenu-arrow {
display: none !important;
}
}
}
......@@ -144,35 +157,37 @@
// }
}
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
background:@active-color !important;
background: @active-color !important;
}
.ant-menu.ant-menu-dark, .ant-menu-dark .ant-menu-sub, .ant-menu.ant-menu-dark .ant-menu-sub{
.ant-menu.ant-menu-dark,
.ant-menu-dark .ant-menu-sub,
.ant-menu.ant-menu-dark .ant-menu-sub {
background: @menu-bakg !important;
}
.ant-menu-submenu-popup{
left:67px !important;
.ant-menu-submenu-popup {
left: 67px !important;
}
.ant-menu-submenu-popup>.ant-menu {
background: @menu-bakg !important;
.ant-menu-submenu-popup > .ant-menu {
background: @menu-bakg !important;
color: #333;
width: 132px;
min-width: auto;
li {
width: calc(100% - 16px);
padding-left: 20px;
margin:12px 8px !important;
&:hover{
background: #F3F6FA;
margin: 12px 8px !important;
&:hover {
background: #f3f6fa;
border-radius: 2px;
color:#333 !important;
color: #333 !important;
}
}
.ant-menu-item-selected {
background: @active-color;
color: #fff;
&:hover{
color: #fff !important;
&:hover {
color: #fff !important;
}
}
......
......@@ -8,142 +8,147 @@
*/
export const menuList: any = [
{
groupName: "中心首页",
groupCode: "CloudPage",
groupName: '中心首页',
groupCode: 'CloudPage',
icon: '&#xe8a7;',
link: '/home',
img:'https://image.xiaomaiketang.com/xm/ni3BFJDT3a.png',
selectImg:'https://image.xiaomaiketang.com/xm/GRDztTAWaM.png'
img: 'https://image.xiaomaiketang.com/xm/ni3BFJDT3a.png',
selectImg: 'https://image.xiaomaiketang.com/xm/GRDztTAWaM.png',
},
{
groupName: "课程管理",
groupCode: "CloudCourse",
groupName: '课程管理',
groupCode: 'CloudCourse',
icon: '&#xe8a5;',
img:'https://image.xiaomaiketang.com/xm/jBGrGjM7HQ.png',
img: 'https://image.xiaomaiketang.com/xm/jBGrGjM7HQ.png',
selectImg: 'https://image.xiaomaiketang.com/xm/TTBGBpf3BJ.png',
children: [
{
groupName: "直播课",
groupCode: "CourseLiveClass",
link: '/live-course'
groupName: '直播课',
groupCode: 'CourseLiveClass',
link: '/live-course',
},
{
groupName: "视频课",
groupCode: "CourseVideoClass",
link: '/video-course'
groupName: '视频课',
groupCode: 'CourseVideoClass',
link: '/video-course',
},
{
groupName: "图文课",
groupCode: "GraphicLesson",
link: '/graphics-course'
groupName: '图文课',
groupCode: 'GraphicLesson',
link: '/graphics-course',
},
{
groupName: "线下课",
groupCode: "OfflineClass",
link: '/offline-course'
groupName: '线下课',
groupCode: 'OfflineClass',
link: '/offline-course',
},
]
],
},
{
groupName: "培训管理",
groupCode: "TrainManage",
groupName: '培训管理',
groupCode: 'TrainManage',
icon: '&#xe8a6;',
img:'https://image.xiaomaiketang.com/xm/Yy6pZ6G6kS.png',
img: 'https://image.xiaomaiketang.com/xm/Yy6pZ6G6kS.png',
selectImg: 'https://image.xiaomaiketang.com/xm/Z8G6NMQhaH.png',
children: [
{
groupName: "培训计划",
groupCode: "TrainPlan",
link: '/plan'
}
groupName: '培训计划',
groupCode: 'TrainPlan',
link: '/plan',
},
],
},
{
groupName: "助学工具",
groupCode: "AidTool",
groupName: '助学工具',
groupCode: 'AidTool',
icon: '&#xe8a9;',
img:'https://image.xiaomaiketang.com/xm/xsma4hx3b3.png',
img: 'https://image.xiaomaiketang.com/xm/xsma4hx3b3.png',
selectImg: 'https://image.xiaomaiketang.com/xm/3QZkdFMCS7.png',
children: [
{
groupName: "题库",
groupCode: "QuestionBank",
link: '/question-manage-index'
groupName: '题库',
groupCode: 'QuestionBank',
link: '/question-manage-index',
},
{
groupName: "试卷",
groupCode: "ExamPaper",
link: '/paper-manage-index'
groupName: '试卷',
groupCode: 'ExamPaper',
link: '/paper-manage-index',
},
{
groupName: "考试",
groupCode: "CloudExam",
link: '/examination-manage-index'
groupName: '考试',
groupCode: 'CloudExam',
link: '/examination-manage-index',
},
]
],
},
{
groupName: "知识库",
groupCode: "CloudKnowledge",
groupName: '知识库',
groupCode: 'CloudKnowledge',
icon: '&#xe8a8;',
link: '/knowledge-base',
img:'https://image.xiaomaiketang.com/xm/8sbP5rGQWh.png',
selectImg:'https://image.xiaomaiketang.com/xm/hJKCfibC22.png'
img: 'https://image.xiaomaiketang.com/xm/8sbP5rGQWh.png',
selectImg: 'https://image.xiaomaiketang.com/xm/hJKCfibC22.png',
},
{
groupName: "资料云盘",
groupCode: "CloudDisk",
groupName: '资料云盘',
groupCode: 'CloudDisk',
icon: '&#xe8aa;',
link: '/resource-disk',
img:'https://image.xiaomaiketang.com/xm/zGKbXJPzXx.png',
selectImg:'https://image.xiaomaiketang.com/xm/5sN4MzjxYc.png',
img: 'https://image.xiaomaiketang.com/xm/zGKbXJPzXx.png',
selectImg: 'https://image.xiaomaiketang.com/xm/5sN4MzjxYc.png',
},
{
groupName: "人员管理",
groupCode: "PersonManage",
groupName: '人员管理',
groupCode: 'PersonManage',
icon: '&#xe8a4;',
img:'https://image.xiaomaiketang.com/xm/PRCnrt35y8.png',
img: 'https://image.xiaomaiketang.com/xm/PRCnrt35y8.png',
selectImg: 'https://image.xiaomaiketang.com/xm/GhkwbdpwfK.png',
children: [
{
groupName: "员工管理",
groupCode: "ShopStaff",
link: '/college-employee'
groupName: '员工管理',
groupCode: 'ShopStaff',
link: '/college-employee',
},
{
groupName: "学员管理",
groupCode: "ShopUser",
link: '/college-user'
}
]
groupName: '学员管理',
groupCode: 'ShopUser',
link: '/college-user',
},
],
},
{
groupName: "学院管理",
groupCode: "CloudShop",
groupName: '学院管理',
groupCode: 'CloudShop',
icon: '&#xe8a4;',
img:'https://image.xiaomaiketang.com/xm/Q8i5RSMKNc.png',
img: 'https://image.xiaomaiketang.com/xm/Q8i5RSMKNc.png',
selectImg: 'https://image.xiaomaiketang.com/xm/pFFF3Wcy3t.png',
children: [
{
groupName: "学院信息",
groupCode: "ShopInfo",
link: '/college-info'
groupName: '学院信息',
groupCode: 'ShopInfo',
link: '/college-info',
},
{
groupName: "学院装修",
groupCode: "ShopDecoration",
link: '/store-decoration'
groupName: '学院装修',
groupCode: 'ShopDecoration',
link: '/store-decoration',
},
{
groupName: "分类管理",
groupCode: "CourseCategory",
link: '/course-category-manage'
groupName: '分类管理',
groupCode: 'CourseCategory',
link: '/course-category-manage',
},
{
groupName: "H5学院",
groupCode: "ShopDecorationH5",
link: '/store-decoration/h5'
groupName: 'H5学院',
groupCode: 'ShopDecorationH5',
link: '/store-decoration/h5',
},
{
groupName: "网页端学院",
groupCode: "ShopDecorationWeb",
link: '/store-decoration/web'
}
]
groupName: '网页端学院',
groupCode: 'ShopDecorationWeb',
link: '/store-decoration/web',
},
],
},
]
\ No newline at end of file
];
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