Commit ef93bd63 by chenshu

fix:merge

parents 72859aca b6a08b23
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 10:57:14
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-13 17:16:44
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import PropTypes from 'prop-types';
import React from 'react'
// import { Modal } from 'antd';
import './TableSelectedData.less';
class TableSelectedData extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className={this.props.className+' selected-data-box'}>
<span className="icon iconfont">&#xe61d;</span>
<span className="selected-text">{'已选择'+this.props.selectedNum+'项'}</span>
<span className="click-clear" onClick={this.props.clearSelectedData}>清空</span>
</div>
)
}
}
TableSelectedData.propTypes = {
className: PropTypes.string, // class
selectedNum: PropTypes.number, // 已选择人数
clearSelectedData: PropTypes.func, // 取消全部选择
};
TableSelectedData.defaultProps = {
className: '',
selectedNum: 0,
clearSelectedData: function () {
}
}
export default TableSelectedData
\ No newline at end of file
.selected-data-box {
display: inline-block;
min-width: 186px;
height: 32px;
line-height: 32px;
background: #FFF4DD;
padding: 0px 16px;
border-radius:4px;
margin: 16px 10px 13px 0;
.iconfont {
color: #FF9D14;
}
.selected-text {
margin-left: 10px;
margin-right: 20px;
}
.click-clear {
float: right;
cursor: pointer;
color: #5289FA;
&:hover {
color: rgba(85, 168, 253, 0.8);
}
}
}
\ No newline at end of file
.header-box {
padding: 30px 16px;
margin: 0 16px 16px;
margin-bottom: 8px;
background: #ffffff;
.course-type {
display: inline-block;
border-radius: 2px;
padding: 0 8px;
font-size: 14px;
font-weight: 400;
line-height: 20px;
}
.course-name {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 22px;
margin-left: 8px;
}
}
import React from "react";
import { Tag } from 'antd'
import "./WatchDataHeader.less";
interface WatchDataHeaderProps {
type: string;
color?: string;
courseName?: string;
className?: string;
}
const WatchDataHeader = (props: WatchDataHeaderProps) => {
const { type, color , className ,courseName} = props;
return (
<div className={className + " header-box"}>
<span className="course-type" style={{color:color,border:`1px solid ${color}`}}>{type}</span>
<span className='course-name'>{courseName}</span>
</div>
);
};
export default WatchDataHeader;
...@@ -659,7 +659,7 @@ td.ant-table-column-sort{ ...@@ -659,7 +659,7 @@ td.ant-table-column-sort{
} }
&:focus, &:focus,
&:active{ &:active{
color:#C6C6C6 !important; color:#666 !important;
border:1px solid #C6C6C6 !important; border:1px solid #C6C6C6 !important;
} }
} }
......
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-12-12 11:57:10 * @Date: 2020-12-12 11:57:10
* @LastEditors: zhangleyuan * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-05 17:20:29 * @LastEditTime: 2021-03-22 13:54:20
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -87,4 +87,10 @@ export function videoScheduleBasePage(params: object) { ...@@ -87,4 +87,10 @@ export function videoScheduleBasePage(params: object) {
} }
export function relatedCourseToPlan(params: object) { export function relatedCourseToPlan(params: object) {
return Service.Hades("public/hades/relatedCourseToPlan", params); return Service.Hades("public/hades/relatedCourseToPlan", params);
} }
\ No newline at end of file export function knowledgeMediaCoursePage(params: object) {
return Service.Hades("public/hades/knowledgeMediaCoursePage", params);
}
export function getCategoryTree(params: object) {
return Service.Hades("public/hades/queryKnowledgeCategoryTree", params);
}
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-19 18:09:35
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-30 09:51:00
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import Service from "@/common/js/service";
class KnowledgeAPI {
// 媒体课列表(视频/图文)
knowledgeMediaCoursePage = (params: object) => {
return Service.Hades("public/hades/knowledgeMediaCoursePage", params);
}
// 直播课列表
knowledgeLiveCoursePage = (params: object) => {
return Service.Hades("public/hades/knowledgeLiveCoursePage", params);
}
// 知识库分类树
getCategoryTree = (params: object) => {
return Service.Hades("public/hades/queryKnowledgeCategoryTree", params);
}
// 查询题目分类树
queryQuestionCategoryTree = (params: object) => {
return Service.Hades("public/hades/queryQuestionCategoryTree", params);
}
// 新增知识
addKnowledge = (params: object) => {
return Service.Hades("public/hades/batchAddKnowledge", params);
}
// 不同类型一起新增知识
addDifTypeKnowledge = (params: object) => {
return Service.Hades("public/hades/batchAddDifTypeKnowledge", params);
}
// 删除知识
delKnowledge = (params: object) => {
return Service.Hades("public/hades/delKnowledge", params);
}
// 移动知识
moveKnowledge = (params: object) => {
return Service.Hades("public/hades/moveKnowledge", params);
}
// 知识库列表
queryPageKnowledgeForManager = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeForManager", params);
}
// 直播课学生观看记录
queryPageKnowledgeLiveStudentVisitData = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeLiveStudentVisitData", params);
}
// 直播课老师观看记录
queryPageKnowledgeLiveTeacherVisitData = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeLiveTeacherVisitData", params);
}
// 分页图文课观看记录
queryPageKnowledgeMediaCourseWatchInfo = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeMediaCourseWatchInfo", params);
}
// 直播课回放学生观看记录
queryPageKnowledgeReplayRecordPage = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeReplayRecordPage", params);
}
// 分页获取知识库包括(子分类)
queryPageKnowledgeInclude = (params: object) => {
return Service.Hades("anon/customerHades/queryPageKnowledgeInclude", params);
}
// 分页云盘资料查看记录
queryPageKnowledgeFolderWatchInfo = (params: object) => {
return Service.Hades("public/hades/queryPageKnowledgeFolderWatchInfo", params);
}
// 资料观看记录导出
exportFolderLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportFolderLearnSync", params);
}
// 直播观看记录导出
exportLiveLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportLiveLearnSync", params);
}
//图文课观看记录导出
exportPicLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportPicLearnSync", params);
}
// 视频课观看记录导出
exportVideoLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportVideoLearnSync", params);
}
}
export default new KnowledgeAPI()
\ No newline at end of file
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-11-25 18:25:02 * @Date: 2020-11-25 18:25:02
* @LastEditors: zhangleyuan * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-05 17:20:56 * @LastEditTime: 2021-03-22 13:58:04
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { import {
fetchLecturerData, fetchUserData, exportStudentCourseData, exportPlayBackCourseData, fetchPlaybackList, createLiveCloudCourse, getLiveCloudCoursePage, fetchLecturerData, getCategoryTree, knowledgeMediaCoursePage, fetchUserData, exportStudentCourseData, exportPlayBackCourseData, fetchPlaybackList, createLiveCloudCourse, getLiveCloudCoursePage,
getLiveCloudCourseDetail, updateLiveCloudCourse, turnOnOrOffLiveCloudCourse, delLiveCloudCourse, changeVideoShelfState, createVideoSchedule, delVideoSchedule, getLiveCloudCourseDetail, updateLiveCloudCourse, turnOnOrOffLiveCloudCourse, delLiveCloudCourse, changeVideoShelfState, createVideoSchedule, delVideoSchedule,
editVideoSchedule, userWatchInfo, videoSchedulePage, videoScheduleDetail, videoWatchInfo, getQrcode,getLiveCloudCourseBasePage,videoScheduleBasePage,relatedCourseToPlan editVideoSchedule, userWatchInfo, videoSchedulePage, videoScheduleDetail, videoWatchInfo, getQrcode, getLiveCloudCourseBasePage, videoScheduleBasePage, relatedCourseToPlan
} from '@/data-source/course/request-api'; } from '@/data-source/course/request-api';
export default class courseService { export default class courseService {
...@@ -85,13 +85,20 @@ export default class courseService { ...@@ -85,13 +85,20 @@ export default class courseService {
static videoWatchInfo(params: any) { static videoWatchInfo(params: any) {
return videoWatchInfo(params); return videoWatchInfo(params);
} }
static getLiveCloudCourseBasePage(params: any){ static getLiveCloudCourseBasePage(params: any) {
return getLiveCloudCourseBasePage(params); return getLiveCloudCourseBasePage(params);
} }
static videoScheduleBasePage(params: any){ static videoScheduleBasePage(params: any) {
return videoScheduleBasePage(params); return videoScheduleBasePage(params);
} }
static relatedCourseToPlan(params: any){ static relatedCourseToPlan(params: any) {
return relatedCourseToPlan(params); return relatedCourseToPlan(params);
} }
static knowledgeMediaCoursePage(params: any) {
return knowledgeMediaCoursePage(params);
}
static getCategoryTree(params: any) {
return getCategoryTree(params);
}
} }
\ No newline at end of file
<!-- <!--
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-24 12:20:57 * @Date: 2020-08-24 12:20:57
* @LastEditors: zhangleyuan * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-27 11:09:24 * @LastEditTime: 2021-04-02 14:58:57
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
--> -->
......
<!-- <!--
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-24 12:20:57 * @Date: 2020-08-24 12:20:57
* @LastEditors: zhangleyuan * @LastEditors: zangsuyun
* @LastEditTime: 2021-04-01 19:55:12 * @LastEditTime: 2021-04-02 14:59:11
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
--> -->
......
...@@ -185,7 +185,7 @@ class LiveCourseFilter extends React.Component { ...@@ -185,7 +185,7 @@ class LiveCourseFilter extends React.Component {
<span>讲师:</span> <span>讲师:</span>
<Select <Select
placeholder="请选择讲师" placeholder="请选择讲师"
style={{ width: 240}} style={{ width: "calc(100% - 70px)"}}
showSearch showSearch
allowClear allowClear
filterOption={(input, option) => option} filterOption={(input, option) => option}
......
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-22 18:24:53
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-27 11:54:42
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
const ENUM = {
courseStateShow: {
UN_START: {
code: 1,
title: "待开课",
color: "#FFB714",
},
STARTING: {
code: 2,
title: "上课中",
color: "#238FFF",
},
FINISH: {
code: 3,
title: "已完成",
color: "#3BBDAA",
},
EXPIRED: {
code: 4,
title: "未成功开课",
color: "#999",
},
},
CourseTypeEnum: {
LIVE: "直播课",
VOICE: "视频课",
PICTURE: "图文课",
FOLDER: "学习资料",
},
};
export default ENUM
\ No newline at end of file
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-19 18:05:23
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-08 11:29:12
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { Component } from "react";
import { Input, Button, Tree } from "antd";
import "./Classification.less";
import User from "@/common/js/user";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
const { Search } = Input;
const { DirectoryTree } = Tree;
class Classification extends Component {
constructor(props) {
super(props);
this.state = {
selectedKeys: props.selectedKeys ? [props.selectedKeys] : ["0"],
searchValue: null,
NewEditQuestionBankCategory: null, //新增或编辑分类模态框
ImportCourseCategory: null, // 引用课程分类模态框
treeData: this.props.treeData || [],
autoExpandParent: false,
};
}
componentDidMount() {
this.queryCategoryTree();
}
shouldComponentUpdate = (nextProps, nextState) => {
const { updateCategoryFlag } = nextProps;
if (this.props.updateCategoryFlag !== updateCategoryFlag) {
this.queryCategoryTree();
}
return true;
};
/** 获取树状第一级key 设置默认展开第一项 */
getFirstLevelKeys = (data) => {
let firstLevelKeys = [];
data.forEach((item) => {
if (item.categoryLevel === 0) {
firstLevelKeys.push(item.key);
}
});
return firstLevelKeys;
};
/** 树状展开事件 */
onExpand = (expandedKeys) => {
this.setState({ expandedKeys });
};
/** 树状选中事件 */
onSelect = (selectedKeys) => {
this.setState({ selectedKeys });
console.log(selectedKeys);
this.props.getSelectedCategoryId(selectedKeys[0]);
};
// 查询分类树
queryCategoryTree = (categoryName) => {
let query = {
categoryName,
storeId: User.getStoreId(),
withCount: true,
};
KnowledgeAPI.getCategoryTree(query).then((res) => {
const { categoryList = [], noCategoryCnt = 0 } = res.result;
let str = "未分类";
if (categoryName) {
this.setState({ autoExpandParent: true });
if (str.indexOf(categoryName) < 0) {
this.setState({
treeData: this.renderTreeNodes(categoryList, categoryName),
});
let nodeId = [];
Object.keys(this.state.treeMap).forEach((item) => {
nodeId.push(item);
});
this.setState({ expandedKeys: nodeId });
} else {
const defaultNode = {
id: "0",
categoryName: "未分类",
categoryCount: noCategoryCnt,
};
categoryList.unshift(defaultNode);
this.setState({
treeData: this.renderTreeNodes(categoryList, categoryName),
});
let nodeId = [];
Object.keys(this.state.treeMap).forEach((item) => {
nodeId.push(item);
});
this.setState({ expandedKeys: nodeId });
}
} else {
this.setState({ autoExpandParent: false });
const defaultNode = {
id: "0",
categoryName: "未分类",
categoryCount: noCategoryCnt,
};
categoryList.unshift(defaultNode);
this.setState({
treeData: this.renderTreeNodes(categoryList, categoryName),
});
this.setState({ expandedKeys: [] });
}
});
};
getTreeMap = (data, map) => {
data.forEach((item) => {
map[item.id] = item;
if (item.sonCategoryList && item.sonCategoryList.length > 0) {
this.getTreeMap(item.sonCategoryList, map);
}
});
return map;
};
renderTreeNodes = (data, value) => {
let newTreeData = data.map((item) => {
item.title = item.categoryName;
item.key = item.id;
item.title =
!value || (value && item.categoryName.indexOf(value) > -1) ? (
<span>
{item.categoryName}{item.categoryCount}
</span>
) : (
<span style={{ opacity: 0.5 }}>
{item.categoryName}{item.categoryCount}
</span>
);
item.icon =
item.categoryName === "未分类" ? (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/defaultCategory.png"
alt=""
/>
) : (
<img
style={{
width: "24px",
height: "24px",
opacity:
!value || (value && item.categoryName.indexOf(value) > -1)
? 1
: 0.5,
}}
src="https://image.xiaomaiketang.com/xm/hasCategory.png"
alt=""
/>
);
if (item.sonCategoryList) {
item.children = this.renderTreeNodes(item.sonCategoryList, value);
}
return item;
});
let map = {};
this.setState({ treeMap: this.getTreeMap(data, map) });
return newTreeData;
};
render() {
const {
treeData,
expandedKeys,
selectedKeys,
autoExpandParent,
} = this.state;
return (
<div className="question-bank-sider">
<div className="sider-title">知识分类</div>
<Search
className="sider-search"
placeholder="搜索名称分类"
onSearch={(value) => {
// TODO 调用查询分类接口
this.queryCategoryTree(value);
}}
enterButton={<span className="icon iconfont">&#xe832;</span>}
/>
<div className="sider-btn">
<Button
onClick={() => {
window.RCHistory.push({
pathname: "/question-category-manage?from=knowledge",
});
}}
>
分类管理
</Button>
</div>
<div className="sider-tree">
<DirectoryTree
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onExpand={this.onExpand}
selectedKeys={selectedKeys}
onSelect={this.onSelect}
showIcon
treeData={treeData}
/>
</div>
{this.state.NewEditQuestionBankCategory}
{this.state.ImportCourseCategory}
</div>
);
}
}
export default Classification;
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-19 18:16:58
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-25 19:13:06
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
.question-bank-sider {
position: relative;
.sider-title {
height: 22px;
font-size: 16px;
font-weight: 500;
color: #000000;
line-height: 22px;
margin-bottom: 16px;
}
.sider-search {
margin-bottom: 16px;
}
.sider-btn {
margin-bottom: 16px;
}
.sider-tree {
width: 266px;
overflow: scroll;
height: ~'calc(100vh - 300px)';
.empty-tree-tip {
text-align: center;
margin-top: 100%;
.empty-tree-btn {
color: #ffb714;
cursor: pointer;
}
}
.ant-tree.ant-tree-directory {
font-size: 14px;
font-weight: 400;
color: #666666;
width: 260px;
.anticon {
color: #666666;
}
.ant-tree-treenode {
height: 44px;
padding: 0;
span {
line-height: 44px;
white-space: nowrap;
}
.ant-tree-node-content-wrapper.ant-tree-node-selected {
color: #666666;
}
}
.ant-tree-treenode-selected:hover::before,
.ant-tree-treenode-selected::before {
background: #fffbf1;
}
}
}
}
.knowledge-base-filter {
position: relative;
.search-condition {
width: calc(100% - 80px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 33%;
max-width: 600px;
margin-right: 3%;
margin-bottom: 12px;
.search-name{
vertical-align: middle;
line-height: 30px;
}
.shelf-status{
width:84px;
display:inline-block;
text-align:right;
}
}
}
.reset-fold-area {
position: absolute;
right: 12px;
}
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
.fold-btn {
font-size: 14px;
color: #666666;
line-height: 20px;
.fold-icon {
font-size: 12px;
margin-left:4px;
}
}
}
.data-icon {
cursor: pointer;
}
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-12 11:16:38
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-08 11:51:42
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import { Row, Input, Select, Tooltip } from "antd";
import "./KnowledgeBase.less";
import ENUM from "../ENUM.js";
const { Search } = Input;
const { Option } = Select;
const DEFAULT_QUERY = {
name: null, // 课程名称
type: null,
};
class KnowledgeBaseFilter extends React.Component {
constructor(props) {
super(props);
this.state = {
query: { ...DEFAULT_QUERY }, // 使用扩展运算符,避免浅拷贝
};
}
// 改变搜索条件
handleChangeQuery = (field, value, flag = true) => {
this.setState(
{
query: {
...this.state.query,
[field]: value,
current: 1,
},
},
() => {
this.props.onChange(this.state.query,flag);
}
);
};
// 重置搜索条件
handleReset = () => {
this.setState(
{
query: DEFAULT_QUERY,
},
() => {
this.props.onChange(this.state.query);
}
);
};
render() {
const {
query: { name, type },
} = this.state;
return (
<div className="knowledge-base-filter">
<Row type="flex" justify="space-between" align="top">
<div className="search-condition">
<div className="search-condition__item">
<span className="search-name">课程名称:</span>
<Search
value={name}
placeholder="搜索课程名称"
onChange={(e) => {
this.handleChangeQuery("name", e.target.value, false);
}}
onSearch={(value) => {
this.handleChangeQuery("name", value);
}}
style={{ width: "calc(100% - 84px)" }}
enterButton={<span className="icon iconfont">&#xe832;</span>}
/>
</div>
<div className="search-condition__item">
<span className="shelf-status">课程类型:</span>
<Select
style={{ width: "calc(100% - 84px)" }}
placeholder="请选择课程类型"
allowClear={true}
value={type}
onChange={(value) => {
this.handleChangeQuery("type", value);
}}
suffixIcon={
<span
className="icon iconfont"
style={{ fontSize: "12px", color: "#BFBFBF" }}
>
&#xe835;
</span>
}
>
{Reflect.ownKeys(ENUM.CourseTypeEnum).map((item) => {
return (
<Option key={item} value={item}>{ENUM.CourseTypeEnum[item]}</Option>
);
})}
</Select>
</div>
</div>
<div className="reset-fold-area">
<Tooltip title="清空筛选">
<span
className="resetBtn iconfont icon"
onClick={this.handleReset}
>
&#xe61b;{" "}
</span>
</Tooltip>
</div>
</Row>
</div>
);
}
}
export default KnowledgeBaseFilter;
.knowledge-base-list {
margin-top: 12px;
.knowledge-list-table{
tbody {
tr{
&:nth-child(even){
background: transparent !important;
td{
background:#FFF !important;
}
}
&:nth-child(odd){
background: #FAFAFA !important;
td{
background: #FAFAFA !important;
}
}
&:hover{
td{
background:#F3f6fa !important;
}
}
}
}
}
.categoryName {
font-size: 14px;
color: #666666;
line-height: 20px;
}
.courseware {
font-size: 14px;
color: #5289fa;
line-height: 20px;
text-align: right;
cursor: pointer;
}
.quota-icon {
color: #5289fa;
cursor: pointer;
}
.operate {
display: flex;
align-items: center;
flex-wrap: wrap;
.operate__item {
color: #5289fa;
cursor: pointer;
&.split {
margin: 0 8px;
color: #bfbfbf;
}
&.disable {
cursor: auto;
color: #cccccc;
}
}
}
.operate-text {
color: #5289fa;
cursor: pointer;
}
.course-start-end {
margin-left: 16px;
width: 78px;
height: 20px;
border-radius: 2px;
border: 1px solid rgba(204, 204, 204, 1);
display: flex;
align-items: center;
cursor: pointer;
white-space: nowrap;
.start-icon {
color: #3296fa;
font-size: 12px;
transform: scale(0.8);
margin: 0 5px;
}
.end-icon {
color: #00d700;
font-size: 12px;
transform: scale(0.8);
margin: 0 5px;
}
.start-end-text {
font-size: 12px;
}
}
}
.live-course-more-menu {
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-radius: 4px;
div {
line-height: 30px;
padding: 0 15px;
cursor: pointer;
&:hover {
background: #f3f6fa;
}
}
}
.tipTitle {
.type {
font-weight: 700;
}
}
.knowledge-base-list {
.record__item {
display: flex;
// align-items: center;
.course-cover {
min-width: 107px;
max-width: 90px;
height: 60px;
border-radius: 6px;
margin-right: 8px;
}
.folder-type {
min-width: 107px;
max-width: 90px;
height: 60px;
border-radius: 6px;
margin-right: 8px;
background-image: url("https://image.xiaomaiketang.com/xm/YNfi45JwFA.png");
background-size: cover;
&.JPG,&.PNG,&.JPEG {
background-image: url("https://image.xiaomaiketang.com/xm/AdpWiMHMet.png");
}
&.PPT {
background-image: url("https://image.xiaomaiketang.com/xm/eDDEZiDwMt.png");
}
&.WORD {
background-image: url("https://image.xiaomaiketang.com/xm/JGeWiiZ7YE.png");
}
&.EXCEL {
background-image: url("https://image.xiaomaiketang.com/xm/p3fDEy63Mc.png");
}
&.PDF {
background-image: url("https://image.xiaomaiketang.com/xm/2W5QAbRQfZ.png");
}
}
.course-name {
font-size: 14px;
font-weight: 500;
color: #333333;
line-height: 20px;
font-weight: bold;
font-family: PingFangSC-Medium, PingFang SC;
max-width: 244px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 20px;
&.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
white-space: normal;
height: 40px;
}
}
.course-time {
font-size: 12px;
font-weight: 400;
color: #666666;
line-height: 20px;
}
.course-status {
font-size: 12px;
line-height: 18px;
display: inline-block;
border-radius: 2px;
padding: 0 8px;
margin-left: 4px;
}
.teacher-assistant {
display: flex;
.teacher {
font-size: 12px;
color: #666666;
max-width: 96px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
padding-top: 2px;
}
.assistant {
font-size: 12px;
color: #666666;
max-width: 96px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
padding-top: 2px;
}
.split {
margin: 0 4px;
color: #bfbfbf;
display: inline-blcok;
}
}
}
}
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-12 14:25:52
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-10 11:23:08
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React, { useState, useEffect } from "react";
import { Button, Menu, Dropdown,message } from "antd";
import SelectPrepareFileModal from "@/modules/prepare-lesson/modal/SelectPrepareFileModal";
import { DownOutlined } from "@ant-design/icons";
import AddCourse from "../modal/AddCourse";
import User from "@/common/js/user";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
export default function KnowledgeBaseOpt({
categoryId,
updateCategoryTree,
onChange,
}) {
const [modal, setModal] = useState(null);
const menu = (
<Menu>
<Menu.Item key="1" style={{ textAlign: "center" }}>
<span onClick={handAddCourse}>添加课程</span>
</Menu.Item>
<Menu.Item key="2" style={{ textAlign: "center" }}>
<span onClick={handleAddFile}>添加资料</span>
</Menu.Item>
</Menu>
);
function handAddCourse() {
let modal = (
<AddCourse
onClose={() => {
setModal(null);
}}
onChange={onChange}
categoryId={categoryId}
updateCategoryTree={updateCategoryTree}
></AddCourse>
);
setModal(modal);
}
function handUpload(refIds) {
const params = {
categoryId: categoryId,
refIds,
storeId: User.getStoreId(),
createId: User.getStoreUserId(),
type: "FOLDER",
};
KnowledgeAPI.addKnowledge(params).then(({ success }) => {
if (success) {
message.success("新增成功");
onChange();
updateCategoryTree();
setModal(null);
}
});
setModal(null);
}
function handleAddFile() {
let modal = (
<SelectPrepareFileModal
multiple={true}
scene="knowledge"
operateType="select"
isOpen={true}
accept=".ppt,.pptx,.doc,.docx,.pdf,.jpg,.jpeg,.png,.xlsx,.xls"
tooltip="支持文件类型:ppt、word、excel、pdf、jpg、jpeg、png"
selectTypeList={["JPG", "JPEG", "PNG",'DOC','PDF','EXCEL','application/msword','application/vnd.ms-powerpoint']} // DOC 包含 .pptx,.docx,.xls.XLSX,WORD:DOC
onClose={() => {
setModal(null);
}}
onSelect={handUpload}
/>
);
setModal(modal);
}
return (
<div className="video-course-opt">
<Dropdown overlay={menu}>
<Button type="primary" className="mr12">
添加知识
<DownOutlined />
</Button>
</Dropdown>
{modal}
</div>
);
}
import React from 'react';
import { withRouter } from "react-router-dom";
import { Table, Button, Modal, message } from 'antd';
import dealTimeDuration from "../../course-manage/utils/dealTimeDuration";
import { PageControl } from "@/components";
// import './DataList.less';
import KnowledgeAPI from "@/data-source/knowledge/request-api";
import User from '@/common/js/user';
const liveTypeMap = {
USER: "普通用户",
ANCHOR: "讲师",
ADMIN: "管理员(助教)",
GUEST: "游客"
};
class PlaybackData extends React.Component {
constructor(props) {
super(props);
const id = getParameterByName("id"); // 课程ID
this.state = {
playbackData: [],
current: 1,
size: 10,
total: 0,
id: id,
storeId: User.getStoreId()
}
}
componentDidMount() {
this.fetchPlaybackList();
}
fetchPlaybackList = (page = 1) => {
const { size, id } = this.state
const params = {
id,
current: page,
size
}
KnowledgeAPI.queryPageKnowledgeReplayRecordPage(params).then((res) => {
if (res.result) {
const { records = [], current, size, total } = res.result;
this.setState({
playbackData: records,
current,
size,
total
});
}
});
};
getPlaybackColumns() {
const columns = [
{
title: "观看用户",
dataIndex: "userName",
},
{
title: "手机号",
dataIndex: "phone"
},
{
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: "lookingDuration",
render: (text) => {
return <span>{text ? dealTimeDuration(text) : '-'}</span>;
},
},
];
return columns;
}
// 导出
handleplaybackExport() {
const { storeId, id } = this.state;
KnowledgeAPI.exportLiveLearnSync({
knowledgeId: id,
exportLiveType: "PLAY_BACK",
storeId
}).then((res) => {
const link = res.result;
this.setState({
link
});
document.getElementById("load-play-back-excel").click();
if(res.success){
message.success("导出成功!")
}
})
}
onShowSizeChange = (current, size) => {
if (current == size) {
return;
}
this.setState({ size }, this.fetchUserData)
}
render() {
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" }}
>
111
</a>
<Button onClick={() => {this.handleplaybackExport()}}>导出</Button>
<Table
bordered
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);
}}
/>
}
</div>
)
}
}
export default withRouter(PlaybackData);
\ No newline at end of file
import React from "react";
import { withRouter } from "react-router-dom";
import { Tabs } from "antd";
import Breadcrumbs from "@/components/Breadcrumbs";
import WatchDataHeader from "@/components/WatchDataHeader";
import CourseData from "./CourseData";
import PlaybackData from "./PlayBackData";
import WatchDataModal from "./WatchDataModal";
// import './WatchData.less';
import ENUM from '../ENUM'
class WatchData extends React.Component {
constructor(props) {
super(props);
const type = getParameterByName("type");
const id = getParameterByName("id");
this.state = {
title: type === 'LIVE' ? "上课数据" : '观看数据',
type,
id
};
}
handChangeTitle = (title) => {
this.setState({
title,
});
};
render() {
const { type, title, id } = this.state;
return (
<div className="page data-list">
<Breadcrumbs
navList={title}
goBack={() => {
RCHistory.goBack();
}}
/>
<WatchDataHeader
type={ENUM.CourseTypeEnum[type]}
courseName={localStorage.getItem("WatchData_CourseName")}
color="#FFB714"
/>
<div className="box">
{type === "LIVE" && (
<Tabs defaultActiveKey="上课记录" onChange={this.handChangeTitle}>
<Tabs.TabPane tab="上课记录" key="上课记录">
<CourseData></CourseData>
</Tabs.TabPane>
<Tabs.TabPane tab="回放记录" key="观看数据">
<PlaybackData></PlaybackData>
</Tabs.TabPane>
</Tabs>
)}
{type !== "LIVE" && (
<WatchDataModal type="videoCourseList" id={id} type={type}/>
)}
</div>
</div>
);
}
}
export default withRouter(WatchData);
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-16 10:18:31
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-30 10:17:59
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import { Table, message, Input, Button } from "antd";
import { PageControl } from "@/components";
import CourseService from "@/domains/course-domain/CourseService";
import User from "@/common/js/user";
// import './WatchDataModal.less';
import dealTimeDuration from "../../course-manage/utils/dealTimeDuration";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
const { Search } = Input;
class WatchDataModal extends React.Component {
constructor(props) {
super(props);
this.state = {
dataSource: [],
size: 10,
query: {
current: 1,
},
totalCount: 0,
};
}
componentDidMount() {
this.handleFetchDataList();
}
// 获取观看视频数据列表
handleFetchDataList = () => {
const { query, size, totalCount } = this.state;
const { id, type } = this.props;
const params = {
...query,
size,
id,
storeId: User.getStoreId(),
};
type === "FOLDER"
? KnowledgeAPI.queryPageKnowledgeFolderWatchInfo(params).then((res) => {
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
})
: KnowledgeAPI.queryPageKnowledgeMediaCourseWatchInfo(params).then(
(res) => {
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
}
);
};
handleChangNickname = (value) => {
const isPhone = (value || "").match(/^\d+$/);
const { query } = this.state;
if (isPhone) {
query.phone = value;
query.nickName = null;
} else {
query.nickName = value;
query.phone = null;
}
query.current = 1;
this.setState({
query,
});
};
onShowSizeChange = (current, size) => {
if (current == size) {
return;
}
this.setState(
{
size,
},
() => {
this.handleFetchDataList();
}
);
};
// 请求表头
parseColumns = () => {
const { type } = this.props;
const columns = [
{
title: "观看用户",
key: "name",
dataIndex: "name",
},
{
title: "手机号",
key: "phone",
dataIndex: "phone",
},
{
title: "观看者类型",
key: "userRole",
dataIndex: "userRole",
},
{
title: "首次观看时间",
key: "firstWatch",
dataIndex: "firstWatch",
render: (val) => {
return formatDate("YYYY-MM-DD H:i", val);
},
},
];
if (type === "VOICE" || type === "PICTURE") {
columns.push({
title: "观看时长",
key: "watchDuration",
dataIndex: "watchDuration",
render: (val) => {
return <span>{val ? dealTimeDuration(val) : "00:00:00"}</span>;
},
});
}
if (type === "PICTURE") {
columns.push({
title: "学习进度",
key: "progress",
dataIndex: "progress",
render: (val) => {
return val === 100 ? "已完成" : <span>{val + "%"}</span>;
},
});
}
return columns;
};
handleExportV5 = () => {
const { query } = this.state;
const { id, type } = this.props;
const params = {
...query,
knowledgeId: id,
storeId: User.getStoreId(),
};
switch (type) {
case "FOLDER":
KnowledgeAPI.exportFolderLearnSync(params).then((res) => {
if (res.result) {
window.open(res.result);
} else {
message.error("导出失败");
}
});
break;
case "VOICE":
KnowledgeAPI.exportVideoLearnSync(params).then((res) => {
if (res.result) {
window.open(res.result);
} else {
message.error("导出失败");
}
});
break;
case "PICTURE":
KnowledgeAPI.exportPicLearnSync(params).then((res) => {
if (res.result) {
window.open(res.result);
} else {
message.error("导出失败");
}
});
break;
default:
break;
}
};
render() {
const { size, dataSource, totalCount, query } = this.state;
return (
<div className="watch-data">
<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 className="filter">
<Button
style={{ height: 32, margin: "16px auto 13px 0" }}
onClick={_.debounce(
() => {
if (!dataSource.length) {
message.warning("暂无数据可导出");
return;
}
this.handleExportV5();
},
500,
true
)}
>
导出
</Button>
</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>
</div>
);
}
}
export default WatchDataModal;
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-12 10:43:10
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-10 16:39:30
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import KnowledgeBaseFilter from "./components/KnowledgeBaseFilter";
import KnowledgeBaseOpt from "./components/KnowledgeBaseOpt";
import KnowledgeBaseList from "./components/KnowledgeBaseList";
import Classification from "./components/Classification";
import KnowledgeAPI from "@/data-source/knowledge/request-api";
import User from "@/common/js/user";
export default class KnowledgeBase extends React.Component {
constructor(props) {
super(props);
this.state = {
query: {
size: 10,
current: 1,
storeId: User.getStoreId(),
categoryId: 0,
},
dataSource: [], // 知识库列表
totalCount: 0, // 知识库数据总条数
categoryId: '0',
updateCategoryFlag: false,
};
}
componentWillMount() {
// 获取知识库列表
this.handleFetchScheduleList();
// this.getCategoryTree()
}
getSelectedCategoryId = (categoryId) => {
this.setState({
categoryId,
});
this.handleFetchScheduleList({ categoryId,current:1 });
};
// 更新分类树
updateCategoryTree = () => {
this.setState({
updateCategoryFlag: !this.state.updateCategoryFlag,
});
};
// 获取知识库列表
handleFetchScheduleList = (_query = {},flag = true) => {
const query = {
...this.state.query,
..._query,
};
// 更新请求参数
this.setState({ query });
flag && KnowledgeAPI.queryPageKnowledgeForManager(query).then((res) => {
// KnowledgeAPI.videoSchedulePage(query).then((res) => {
const { result = {} } = res || {};
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
});
};
render() {
const {
dataSource,
totalCount,
query,
categoryId,
updateCategoryFlag,
} = this.state;
return (
<div className="page">
<div className="content-header">知识库</div>
<div className="box" style={{ display: "flex" }}>
{/* 搜索模块 */}
<div className="left" style={{ width: 245 }}>
<Classification
updateCategoryFlag={updateCategoryFlag}
categoryId={categoryId}
getSelectedCategoryId={this.getSelectedCategoryId}
/>
</div>
<div
className="liner"
style={{ backgroundColor: "rgb(238, 238, 238)", width: 0.5, margin: "1px 16px 1px 2px" }}
></div>
<div className="right" style={{ width: "calc(100% - 285px)" }}>
<KnowledgeBaseFilter onChange={this.handleFetchScheduleList} />
{/* 操作模块 */}
{categoryId != 0 && <KnowledgeBaseOpt
onChange={this.handleFetchScheduleList}
updateCategoryTree={this.updateCategoryTree}
categoryId={categoryId}
/>}
{/* 知识库列表模块 */}
<KnowledgeBaseList
query={query}
categoryId={categoryId}
dataSource={dataSource}
totalCount={totalCount}
onChange={this.handleFetchScheduleList}
updateCategoryTree={this.updateCategoryTree}
/>
</div>
</div>
</div>
);
}
}
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 14:38:49
* @LastEditors: zangsuyun
* @LastEditTime: 2021-03-16 15:20:51
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import { Table, Modal, message, Dropdown, Button, Switch, Tooltip } from "antd";
import { Route, withRouter } from "react-router-dom";
import { PageControl } from "@/components";
import "./LiveList.less";
import TableSelectedData from "@/components/TableSelectedData";
import CourseService from "@/domains/course-domain/CourseService";
import User from "@/common/js/user";
import _ from "underscore";
const { confirm } = Modal;
const courseStateShow = {
UN_START: {
code: 1,
title: "待开课",
color: "#FFB714",
},
STARTING: {
code: 2,
title: "上课中",
color: "#238FFF",
},
FINISH: {
code: 3,
title: "已完成",
color: "#3BBDAA",
},
EXPIRED: {
code: 4,
title: "未成功开课",
color: "#999",
},
};
class LiveList extends React.Component {
constructor(props) {
super(props);
this.state = {
columns: [],
courseList: [], // 直播课列表
selectedRowKeys: [],
query: {
current: 1,
size: 10,
},
total: 0,
};
}
componentDidUpdate(prevProps, prevState) {
//必须写在if里面并且重新进行一次this.props !== prevProps的判断
if (
this.props.courseName !== prevProps.courseName ||
this.props.courseType !== prevProps.courseType
) {
this.handleFetchLiveList(this.props);
}
}
componentWillMount() {
this.handleFetchLiveList(this.state.query);
this.parseColumns();
}
// 获取直播课列表
handleFetchLiveList = (_query) => {
const { query } = this.state;
const params = {
...query,
..._query,
storeId: User.getStoreId(),
};
this.setState({ query: params });
CourseService.getLiveCloudCoursePage(params).then((res) => {
const {
result: { records = [], total },
} = res;
this.setState({
total,
courseList: records,
});
});
};
parseColumns = () => {
let columns;
columns = [
{
title: (
<span>
<span>课程信息</span>
<Tooltip
title={<div>已加入该分类的课程不支持重复选择,因此不显示。</div>}
>
<i
className="icon iconfont"
style={{
marginLeft: "5px",
cursor: "pointer",
color: "#bfbfbf",
fontSize: "14px",
}}
>
&#xe61d;
</i>
</Tooltip>
</span>
),
width: 371,
key: "course",
dataIndex: "courseName",
render: (val, record) => {
let hasCover = false;
return (
<div className="record__item">
{record.courseMediaVOS.map((item, index) => {
if (item.contentType === "COVER") {
hasCover = true;
return <img className="course-cover" src={item.mediaUrl} />;
}
})}
{!hasCover && (
<img
className="course-cover"
src={"https://image.xiaomaiketang.com/xm/YNfi45JwFA.png"}
/>
)}
<div>
{record.courseName.length > 17 ? (
<Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div>
</Tooltip>
) : (
<div className="course-name">{record.courseName}</div>
)}
<div>
<span
className="course-status"
style={{
color: courseStateShow[record.courseState].color,
border: `1px solid ${
courseStateShow[record.courseState].color
}`,
}}
>
{courseStateShow[record.courseState].title}
</span>
</div>
</div>
</div>
);
},
},
{
title: "上课时间",
// width: "10%",
key: "couseCatalog",
dataIndex: "couseCatalog",
render: (val, item) => {
return (
<span className="course-time">
{formatDate("YYYY-MM-DD", parseInt(item.startTime))} <br></br>
{formatDate("H:i", parseInt(item.startTime))}~
{formatDate("H:i", parseInt(item.endTime))}
</span>
);
},
},
{
title: "课程分类",
// width: "10%",
key: "couseCatalog",
dataIndex: "couseCatalog",
render: (val, item) => {
return <div className="categoryName">{item.categoryName}</div>;
},
},
];
this.setState({ columns });
};
onShowSizeChange = (current, size) => {
if (current == size) {
return;
}
let _query = this.state.query;
_query.size = size;
this.handleFetchLiveList(_query);
};
selectVideoList = (record, selected) => {
let { selectedRowKeys } = this.state;
let _list = [];
if (
selected ||
!_.find(
selectedRowKeys,
(item) => item.liveCourseId == record.liveCourseId
)
) {
_list = _.uniq(
selectedRowKeys.concat([record]),
false,
(item) => item.liveCourseId
);
} else {
_list = _.reject(
selectedRowKeys,
(item) => item.liveCourseId === record.liveCourseId
);
}
this.setState({ selectedRowKeys: _list });
};
render() {
const {
columns,
total,
query,
courseList,
loading,
selectedRowKeys,
} = this.state;
const { current, size } = query;
const rowSelection = {
selectedRowKeys: _.pluck(selectedRowKeys, "liveCourseId"),
onSelect: this.selectVideoList,
onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = [];
if (selected) {
_list = _.uniq(
selectedRowKeys.concat(changeRows),
false,
(item) => item.liveCourseId
);
} else {
_list = _.reject(selectedRowKeys, (item) =>
_.find(
changeRows,
(data) => data.liveCourseId === item.liveCourseId
)
);
}
this.setState({ selectedRowKeys: _list });
},
};
return (
<div className="live-list">
<TableSelectedData
selectedNum={selectedRowKeys.length}
clearSelectedData={() => {
this.setState({
selectedRowKeys: [],
});
}}
/>
<Table
bordered
size="middle"
pagination={false}
columns={columns}
rowSelection={rowSelection}
loading={loading}
dataSource={courseList}
rowKey={(row) => row.liveCourseId}
/>
{total > 0 && (
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={parseInt(total)}
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.handleFetchLiveList(_query);
}}
onShowSizeChange={this.onShowSizeChange}
/>
</div>
)}
</div>
);
}
}
export default withRouter(LiveList);
.live-list {
.record__item {
display: flex;
align-items: center;
.course-cover {
min-width: 107px;
max-width: 107px;
height: 60px;
border-radius: 6px;
margin-right: 8px;
}
.course-name {
font-size: 14px;
font-weight: 400;
color: #666666;
font-family: PingFangSC-Regular, PingFang SC;
line-height: 20px;
max-width: 244px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.course-time {
font-size: 12px;
font-weight: 400;
color: #666666;
line-height: 20px;
}
.course-status {
font-size: 12px;
line-height: 17px;
display: inline-block;
border-radius: 2px;
padding: 0 8px;
}
.teacher-assistant {
display: flex;
.teacher {
font-size: 12px;
color: #666666;
max-width: 96px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
padding-top: 2px;
}
.assistant {
font-size: 12px;
color: #666666;
max-width: 96px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
padding-top: 2px;
}
.split {
margin: 0 4px;
color: #bfbfbf;
display: inline-blcok;
}
}
}
.categoryName {
font-size: 14px;
color: #666666;
line-height: 20px;
}
.courseware {
font-size: 14px;
color: #5289fa;
line-height: 20px;
text-align: right;
cursor: pointer;
}
.quota-icon {
color: #5289fa;
cursor: pointer;
}
.operate {
display: flex;
align-items: center;
flex-wrap: wrap;
.operate__item {
color: #5289fa;
cursor: pointer;
&.split {
margin: 0 8px;
color: #bfbfbf;
}
}
}
.operate-text {
color: #5289fa;
cursor: pointer;
}
.course-start-end {
margin-left: 16px;
width: 78px;
height: 20px;
border-radius: 2px;
border: 1px solid rgba(204, 204, 204, 1);
display: flex;
align-items: center;
cursor: pointer;
white-space: nowrap;
.start-icon {
color: #3296fa;
font-size: 12px;
transform: scale(0.8);
margin: 0 5px;
}
.end-icon {
color: #00d700;
font-size: 12px;
transform: scale(0.8);
margin: 0 5px;
}
.start-end-text {
font-size: 12px;
}
}
}
.add-course-modal {
.ant-tabs-top > .ant-tabs-nav::before {
border-bottom: 0px;
}
.ant-tabs-nav-list {
margin: 0 auto;
flex:none !important
}
.ant-tabs-tab.ant-tabs-tab-active .ant-tabs-tab-btn {
font-weight: normal;
border-bottom: 0px;
}
.ant-tabs-nav .ant-tabs-tab {
padding: 6px 12px !important;
margin: 0;
border: 0.5px solid #e8e8e8;
font-size: 14px !important;
color: #999;
&:nth-child(1) {
border-radius: 4px 0px 0px 4px;
}
&:nth-child(3) {
border-radius: 0px 4px 4px 0px;
}
}
.ant-tabs-nav .ant-tabs-tab-active {
border: 1px solid #ffb714;
color: #ffb714;
}
.ant-tabs-top .ant-tabs-ink-bar-animated:after {
height: 0;
}
.ant-modal-content tr > td{
padding:12px 8px !important;
}
}
/*
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-13 11:48:24
* @LastEditors: zangsuyun
* @LastEditTime: 2021-04-01 11:58:46
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from "react";
import { Table, Modal, message, Tooltip, Switch, Dropdown } from "antd";
import { PageControl } from "@/components";
import _ from "underscore";
import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass";
import { appId, shareUrl, LIVE_SHARE } from "@/domains/course-domain/constants";
import TableSelectedData from "@/components/TableSelectedData";
import "./LiveList.less";
import CourseService from "@/domains/course-domain/CourseService";
import User from "@/common/js/user";
const ENV = process.env.DEPLOY_ENV || "dev";
class VideoList extends React.Component {
constructor(props) {
super(props);
this.state = {
id: "", // 视频课ID
studentIds: [],
selectedRowKeys: [],
query: {
size: 10,
current: 1,
storeId: User.getStoreId(),
},
dataSource: [], // 视频课列表
totalCount: 0, // 视频课数据总条数
};
}
componentDidUpdate(prevProps, prevState) {
//必须写在if里面并且重新进行一次this.props !== prevProps的判断
if (
((this.props.courseName || this.props.courseType) &&
this.props.courseName !== prevProps.courseName) ||
this.props.courseType !== prevProps.courseType
) {
this.handleFetchScheduleList(this.props);
}
}
componentWillMount() {
// 获取视频课列表
this.handleFetchScheduleList();
}
// 获取视频课列表
handleFetchScheduleList = (_query = {}) => {
const query = {
...this.state.query,
..._query,
};
// 更新请求参数
this.setState({ query });
CourseService.videoSchedulePage(query).then((res) => {
const { result = {} } = res || {};
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
});
};
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;
};
// 请求表头
parseColumns = () => {
const columns = [
{
title: (
<span>
<span>课程信息</span>
<Tooltip
title={
<div>
已加入该分类的课程不支持重复选择,因此不显示。
</div>
}
>
<i
className="icon iconfont"
style={{
marginLeft: "5px",
cursor: "pointer",
color: "#bfbfbf",
fontSize: "14px",
}}
>
&#xe61d;
</i>
</Tooltip>
</span>
),
key: "scheduleName",
dataIndex: "scheduleName",
width: 371,
render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record;
return (
<div className="record__item">
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img
className="course-cover"
src={
coverUrl ||
`${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
{record.courseName.length > 25 ? (
<Tooltip title={record.courseName}>
<div className="course-name">{record.courseName}</div>
</Tooltip>
) : (
<div className="course-name">{record.courseName}</div>
)}
</div>
);
},
},
{
title: "课程时长",
key: "videoDuration",
dataIndex: "videoDuration",
render: (text, item) => {
return <span>{text ? this.dealTimeDuration(text) : "-"}</span>;
},
},
{
title: "课程分类",
key: "categoryName",
dataIndex: "categoryName",
render: (val, record) => {
return (
<div className="record__item">
{record.categoryOneName}
{record.categoryTwoName ? `-${record.categoryTwoName}` : ""}
</div>
);
},
},
];
return columns;
};
selectLiveList = (record, selected) => {
let { selectedRowKeys } = this.state;
let _list = [];
if (selected || !_.find(selectedRowKeys, (item) => item.id == record.id)) {
_list = _.uniq(
selectedRowKeys.concat([record]),
false,
(item) => item.id
);
} else {
_list = _.reject(selectedRowKeys, (item) => item.id === record.id);
}
this.setState({ selectedRowKeys: _list });
};
render() {
const { dataSource = [], totalCount, query, selectedRowKeys } = this.state;
const { current, size } = query;
const rowSelection = {
selectedRowKeys: _.pluck(selectedRowKeys, "id"),
onSelect: this.selectLiveList,
onSelectAll: (selected, _selectedRows, changeRows) => {
let _list = [];
if (selected) {
_list = _.uniq(
selectedRowKeys.concat(changeRows),
false,
(item) => item.id
);
} else {
_list = _.reject(selectedRowKeys, (item) =>
_.find(changeRows, (data) => data.id === item.id)
);
}
this.setState({ selectedRowKeys: _list });
},
};
return (
<div className="live-list">
<TableSelectedData
selectedNum={selectedRowKeys.length}
clearSelectedData={() => {
this.setState({
selectedRowKeys: [],
});
}}
/>
<Table
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
size="middle"
rowSelection={rowSelection}
pagination={false}
bordered
className="video-list-table"
/>
<div className="box-footer">
{totalCount > 0 && (
<PageControl
current={current - 1}
pageSize={size}
total={totalCount}
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.handleFetchScheduleList(_query);
}}
/>
)}
</div>
</div>
);
}
}
export default VideoList;
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2020-11-27 15:06:31 * @Date: 2020-11-27 15:06:31
* @LastEditors: zhangleyuan * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-09 14:22:10 * @LastEditTime: 2021-03-22 13:55:24
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
......
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-23 18:28:50 * @Date: 2021-02-23 18:28:50
* @LastEditors: yuananting * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-24 17:18:20 * @LastEditTime: 2021-03-29 16:14:02
* @Description: 助学工具-题库-主页面分类管理 * @Description: 助学工具-题库-主页面分类管理
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -582,14 +582,12 @@ class QuestionCategoryManage extends Component { ...@@ -582,14 +582,12 @@ class QuestionCategoryManage extends Component {
} = this.state; } = this.state;
return ( return (
<div className="page question-category-manage"> <div className="page question-category-manage">
{getParameterByName("from") === "aid" ? ( {getParameterByName("from") ? (
<Breadcrumbs <Breadcrumbs
navList="课程分类" navList="课程分类"
goBack={() => // goBack={() =>
window.RCHistory.push({ // window.RCHistory.goBack()
pathname: "/question-bank-index", // }
})
}
/> />
) : ( ) : (
<div className="content-header">课程分类</div> <div className="content-header">课程分类</div>
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-04-29 10:26:32 * @Date: 2020-04-29 10:26:32
* @LastEditors: yuananting * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-18 11:30:15 * @LastEditTime: 2021-04-07 16:12:14
* @Description: 内容线路由配置 * @Description: 内容线路由配置
*/ */
import Home from '@/modules/home/Home'; import Home from '@/modules/home/Home';
...@@ -27,6 +27,7 @@ import PlanPage from '@/modules/plan-manage/PlanPage'; ...@@ -27,6 +27,7 @@ import PlanPage from '@/modules/plan-manage/PlanPage';
import AddPlanPage from '@/modules/plan-manage/AddPlan'; import AddPlanPage from '@/modules/plan-manage/AddPlan';
import LearningDataPage from '@/modules/plan-manage/LearningData'; import LearningDataPage from '@/modules/plan-manage/LearningData';
import StoreInfoPage from '@/modules/store-manage/StoreInfo'; import StoreInfoPage from '@/modules/store-manage/StoreInfo';
import KnowledgeBase from "@/modules/knowledge-base/index";
import CollegeInfoPage from '@/modules/college-manage/CollegeInfoPage'; import CollegeInfoPage from '@/modules/college-manage/CollegeInfoPage';
import QuestionBankIndex from '@/modules/teach-tool/QuestionBankIndex'; import QuestionBankIndex from '@/modules/teach-tool/QuestionBankIndex';
import QuestionCategoryManage from '@/modules/teach-tool/QuestionCategoryManage'; import QuestionCategoryManage from '@/modules/teach-tool/QuestionCategoryManage';
...@@ -34,14 +35,14 @@ import AddNewQuestion from '@/modules/teach-tool/AddNewQuestion'; ...@@ -34,14 +35,14 @@ import AddNewQuestion from '@/modules/teach-tool/AddNewQuestion';
const mainRoutes = [ const mainRoutes = [
{ {
path: '/home', path: "/home",
component: Home, component: Home,
name: '中心首页' name: "中心首页",
}, },
{ {
path: '/employees-manage', path: "/employees-manage",
component: EmployeesManagePage, component: EmployeesManagePage,
name: '员工管理' name: "员工管理",
}, },
{ {
path: '/college-employee', path: '/college-employee',
...@@ -54,9 +55,9 @@ const mainRoutes = [ ...@@ -54,9 +55,9 @@ const mainRoutes = [
name: '个人信息' name: '个人信息'
}, },
{ {
path: '/user-manage', path: "/user-manage",
component: UserManagePage, component: UserManagePage,
name: '用户管理' name: "用户管理",
}, },
{ {
path: '/college-user', path: '/college-user',
...@@ -68,75 +69,81 @@ const mainRoutes = [ ...@@ -68,75 +69,81 @@ const mainRoutes = [
component: StoreDecorationPage, component: StoreDecorationPage,
name: '学院装修' name: '学院装修'
}, },
// {
// path: "/course-catalog",
// component: CourseCatalogPage,
// name: "课程分类",
// },
{ {
path: '/course-catalog', path: "/live-course",
component:CourseCatalogPage, component: LiveCoursePage,
name: '课程分类' name: "直播课",
}, },
{ {
path: '/live-course', path: "/video-course",
component:LiveCoursePage, component: VideoCoursePage,
name: '直播课' name: "视频课",
}, },
{ {
path: '/video-course', path: "/graphics-course",
component:VideoCoursePage, component: GraphicsCoursePage,
name: '视频课' name: "图文课",
}, },
{ {
path: '/graphics-course', path: "/create-live-course",
component: GraphicsCoursePage, component: AddLivePage,
name: '图文课' name: "创建直播课",
}, },
{ {
path: '/create-live-course', path: "/create-video-course",
component:AddLivePage, component: AddVideoCoursePage,
name: '创建直播课' name: "创建视频课",
}, },
{ {
path: '/create-video-course', path: "/knowledge-base",
component:AddVideoCoursePage, // component:ResourceDisk,
name: '创建视频课' component: KnowledgeBase,
name: "知识库",
}, },
{ {
path: '/create-graphics-course', path: "/create-graphics-course",
component:AddGraphicsCoursePage, component: AddGraphicsCoursePage,
name: '创建图文课' name: "创建图文课",
}, },
{ {
path: '/resource-disk', path: "/resource-disk",
component:ResourceDisk, component: ResourceDisk,
name: '资料云盘' name: "资料云盘",
}, },
{ {
path: '/question-bank-index', path: "/question-bank-index",
component:QuestionBankIndex, component: QuestionBankIndex,
name: '题库' name: "题库",
}, },
{ {
path: '/question-category-manage', path: "/question-category-manage",
component:QuestionCategoryManage, component: QuestionCategoryManage,
name: '分类管理' name: "分类管理",
}, },
{ {
path: '/create-new-question', path: "/create-new-question",
component:AddNewQuestion, component: AddNewQuestion,
name: '新增题目' name: "新增题目",
}, },
{ {
path: '/switch-route', path: "/switch-route",
component: SwitchRoute, component: SwitchRoute,
name: '登录后跳转承载页' name: "登录后跳转承载页",
}, },
{ {
path:'/plan', path: "/plan",
component: PlanPage, component: PlanPage,
name: '培训计划' name: "培训计划",
}, },
{ {
path: '/create-plan', path: "/create-plan",
component:AddPlanPage, component: AddPlanPage,
name: '创建视频课' name: "创建视频课",
}, },
{ {
path: '/store-info', path: '/store-info',
...@@ -149,11 +156,10 @@ const mainRoutes = [ ...@@ -149,11 +156,10 @@ const mainRoutes = [
name: '学院信息' name: '学院信息'
}, },
{ {
path: '/learning-data', path: "/learning-data",
component:LearningDataPage, component: LearningDataPage,
name: '学习数据' name: "学习数据",
} },
];
]
export default mainRoutes; export default mainRoutes;
\ No newline at end of file
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-02-21 15:53:31 * @Date: 2021-02-21 15:53:31
* @LastEditors: yuananting * @LastEditors: zangsuyun
* @LastEditTime: 2021-03-19 15:31:56 * @LastEditTime: 2021-03-27 10:32:29
* @Description: 描述一下咯 * @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -36,6 +36,12 @@ export const menuList: any = [ ...@@ -36,6 +36,12 @@ export const menuList: any = [
] ]
}, },
{ {
groupName: "知识库",
groupCode: "CloudKnowledge",
icon: '&#xe840;',
link: '/knowledge-base'
},
{
groupName: "资料云盘", groupName: "资料云盘",
groupCode: "CloudDisk", groupCode: "CloudDisk",
icon: '&#xe83b;', icon: '&#xe83b;',
......
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