Commit 030ce89c by maolipeng

Merge branch 'dev' of…

Merge branch 'dev' of ssh://xmgit.ixm5.cn:10022/xiaomai-cloud-class/xiaomai-cloud-class-web into dev

# Conflicts:
#	src/data-source/base/request-apis.ts
#	src/domains/basic-domain/baseService.ts
#	src/index.html
#	src/index.tsx
#	src/modules/course-manage/components/LiveCourseList.jsx
#	src/modules/course-manage/components/LiveCourseOpt.jsx
#	src/modules/course-manage/graphics-course/components/GraphicsCourseList.jsx
#	src/modules/home/Home.jsx
#	src/modules/root/Header.jsx
#	src/modules/root/Login.jsx
#	src/modules/root/Menu.tsx
#	src/modules/teach-tool/examination-manager/AddExam.tsx
#	src/modules/teach-tool/paper-manage/OperatePaper.jsx
parents f0de3604 f89f975e
...@@ -13,8 +13,9 @@ ...@@ -13,8 +13,9 @@
} }
.container { .container {
overflow: scroll; overflow-y: auto;
height: 100%;; overflow-x: hidden;
height: 100%;
.course-cover, .course-url { .course-cover, .course-url {
width: 100%; width: 100%;
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
} }
} }
.operate{ .operate{
display:inline-block;
margin-top:24px; margin-top:24px;
.btn { .btn {
padding:5px 12px; padding:5px 12px;
......
...@@ -133,12 +133,13 @@ const FileTypeIcon = { ...@@ -133,12 +133,13 @@ const FileTypeIcon = {
PPTX: "https://image.xiaomaiketang.com/xm/847pFAdYGW.png", PPTX: "https://image.xiaomaiketang.com/xm/847pFAdYGW.png",
PDF: "https://image.xiaomaiketang.com/xm/rrEJMNkhTG.png", PDF: "https://image.xiaomaiketang.com/xm/rrEJMNkhTG.png",
MP3: "https://image.xiaomaiketang.com/xm/ykjnSWDyQ6.png", MP3: "https://image.xiaomaiketang.com/xm/ykjnSWDyQ6.png",
MP4: "https://image.xiaomaiketang.com/xm/whSYMTdR57.png", MP4: "https://image.xiaomaiketang.com/xm/yK3ASiS8ch.png",
JPG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png", JPG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png",
JPEG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png", JPEG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png",
PNG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png", PNG: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png",
GIF: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png", GIF: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png",
BMP: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png", BMP: "https://image.xiaomaiketang.com/xm/XRkX8JBTPs.png",
VIDEO: 'https://image.xiaomaiketang.com/xm/yK3ASiS8ch.png'
}; };
const UploadIcon = "https://image.xiaomaiketang.com/xm/4DXNrZWWsd.png"; const UploadIcon = "https://image.xiaomaiketang.com/xm/4DXNrZWWsd.png";
......
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-31 09:34:31 * @Date: 2020-08-31 09:34:31
* @LastEditors: Please set LastEditors * @LastEditors: yuananting
* @LastEditTime: 2021-06-24 19:34:21 * @LastEditTime: 2021-07-14 10:49:14
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -115,6 +115,10 @@ class Axios { ...@@ -115,6 +115,10 @@ class Axios {
window.RCHistory.replace('/login'); window.RCHistory.replace('/login');
return Promise.reject(); return Promise.reject();
break; break;
case 504:
message.error('网络状况不稳定,如果出现数据异常,请刷新页面');
Promise.reject();
break;
default: default:
message.error(error.message); message.error(error.message);
break; break;
......
.ant-popover .ant-popover-content .ant-popover-inner { .contact-widget-popover .ant-popover-content .ant-popover-inner {
box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.06); box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.06);
.ant-popover-inner-content { .ant-popover-inner-content {
padding: 0; padding: 0;
......
...@@ -27,6 +27,7 @@ function Content() { ...@@ -27,6 +27,7 @@ function Content() {
export default function ContactWidget(props:ContactWidgetProps) { export default function ContactWidget(props:ContactWidgetProps) {
return <Popover return <Popover
className="contact-widget-popover"
placement={props.placement} placement={props.placement}
arrowPointAtCenter arrowPointAtCenter
content={Content} content={Content}
......
...@@ -88,8 +88,6 @@ class ImgClipModal extends React.Component { ...@@ -88,8 +88,6 @@ class ImgClipModal extends React.Component {
checkOrientation={false} checkOrientation={false}
cropBoxResizable={false} cropBoxResizable={false}
center={true} center={true}
// minCropBoxWidth={cropBoxWidth}
// minCropBoxHeight={cropBoxHeight}
cropBoxMovable={false} cropBoxMovable={false}
dragMode='move' dragMode='move'
onInitialized={(instance) => { onInitialized={(instance) => {
...@@ -108,13 +106,6 @@ class ImgClipModal extends React.Component { ...@@ -108,13 +106,6 @@ class ImgClipModal extends React.Component {
console.log("ratio++++",ratio); console.log("ratio++++",ratio);
this.state.cropperInstace.setCanvasData({width:500}); this.state.cropperInstace.setCanvasData({width:500});
const that = this; const that = this;
// const containerData = this.state.cropperInstace.getContainerData();
// // Zoom to 50% from the center of the container.
// this.state.cropperInstace.zoomTo(.5, {
// x: containerData.width / 2,
// y: containerData.height / 2,
// });
document.querySelector('.cropper__box').addEventListener('dblclick', function (e) { document.querySelector('.cropper__box').addEventListener('dblclick', function (e) {
that.state.cropperInstace.rotate(90) that.state.cropperInstace.rotate(90)
......
...@@ -1156,3 +1156,15 @@ window.XMShowClassName = (date, itemName) => { ...@@ -1156,3 +1156,15 @@ window.XMShowClassName = (date, itemName) => {
} }
return 'new-icon' return 'new-icon'
} }
// 格式化时间段为时分
window.formatDuration = function (time) {
const diff = Math.floor(time % 3600);
let hours = Math.floor(time / 3600);
let mins = Math.floor(diff / 60);
let seconds = Math.floor(time % 60);
hours = hours < 10 ? ("0" + hours) : hours;
mins = mins < 10 ? ("0" + mins) : mins;
seconds = seconds < 10 ? ("0" + seconds) : seconds;
return hours + ":" + mins + ":" + seconds;
};
\ No newline at end of file
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-03 15:13:12 * @Date: 2021-03-03 15:13:12
* @LastEditors: Please set LastEditors * @LastEditors: yuananting
* @LastEditTime: 2021-06-22 14:31:46 * @LastEditTime: 2021-07-09 16:58:34
* @Description: 助学工具接口 * @Description: 助学工具接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -88,3 +88,7 @@ export function batchQueryQuestionDetails(params: object) { ...@@ -88,3 +88,7 @@ export function batchQueryQuestionDetails(params: object) {
export function queryQuestionPageListWithContent(params: object) { export function queryQuestionPageListWithContent(params: object) {
return Service.Hades('public/hades/queryQuestionPageListWithContent', params); return Service.Hades('public/hades/queryQuestionPageListWithContent', params);
} }
export function queryCategoryTreeByPackage(params: object) {
return Service.Hades('public/externalHades/queryPackageCategory', params);
}
\ No newline at end of file
...@@ -2,14 +2,14 @@ ...@@ -2,14 +2,14 @@
* @Author: wufan * @Author: wufan
* @Date: 2020-12-01 17:21:21 * @Date: 2020-12-01 17:21:21
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-25 11:04:13 * @LastEditTime: 2021-07-09 15:33:33
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import Service from "@/common/js/service"; import Service from "@/common/js/service";
import User from "@/common/js/user"; import User from "@/common/js/user";
import axios from 'axios'; import axios from 'axios';
export function sendLoginAuthCode(params: object) { export function sendLoginAuthCode(params: object) {
return Service.Hades("anon/hades/sendLoginAuthCode", params); return Service.Hades("anon/hades/sendLoginAuthCode", params);
} }
...@@ -61,6 +61,9 @@ export function saveYoZoFileVersionId(params: object) { ...@@ -61,6 +61,9 @@ export function saveYoZoFileVersionId(params: object) {
export function yoZoUpload(ossUrl:String,appId:String,uploadSign:String){ export function yoZoUpload(ossUrl:String,appId:String,uploadSign:String){
return axios.post(`https://dmc.yozocloud.cn/api/file/http?fileUrl=${ossUrl}&appId=${appId}&sign=${uploadSign}`) return axios.post(`https://dmc.yozocloud.cn/api/file/http?fileUrl=${ossUrl}&appId=${appId}&sign=${uploadSign}`)
} }
export function saveFileVersionIdByCourseChapter(params: object) {
return Service.Hades('public/hades/saveFileVersionIdByCourseChapter', params);
}
export const getOssClient = ( export const getOssClient = (
data: object, data: object,
instId: string, instId: string,
......
/* /*
* @Author: wufan * @Author: wufan
* @Date: 2020-12-12 11:57:10 * @Date: 2020-12-12 11:57:10
* @LastEditors: zangsuyun * @LastEditors: wufan
* @LastEditTime: 2021-03-22 13:54:20 * @LastEditTime: 2021-07-05 15:07:13
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -57,7 +57,7 @@ export function getLiveCloudCourseBasePage(params: object) { ...@@ -57,7 +57,7 @@ export function getLiveCloudCourseBasePage(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCourseBasePage", params); return Service.Hades("public/courseCloud/getLiveCloudCourseBasePage", params);
} }
//视频课相关接口 //线上课相关接口
export function changeVideoShelfState(params: object) { export function changeVideoShelfState(params: object) {
return Service.Hades("public/hades/changeVideoShelfState", params); return Service.Hades("public/hades/changeVideoShelfState", params);
} }
...@@ -73,6 +73,9 @@ export function editVideoSchedule(params: object) { ...@@ -73,6 +73,9 @@ export function editVideoSchedule(params: object) {
export function userWatchInfo(params: object) { export function userWatchInfo(params: object) {
return Service.Hades("public/hades/userWatchInfo", params); return Service.Hades("public/hades/userWatchInfo", params);
} }
export function lineDetailWatchInfo(params: object) {
return Service.Hades("public/hades/lineDetailWatchInfo", params);
}
export function videoScheduleDetail(params: object) { export function videoScheduleDetail(params: object) {
return Service.Hades("public/hades/videoScheduleDetail", params); return Service.Hades("public/hades/videoScheduleDetail", params);
} }
......
...@@ -81,7 +81,7 @@ class KnowledgeAPI { ...@@ -81,7 +81,7 @@ class KnowledgeAPI {
exportPicLearnSync = (params: object) => { exportPicLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportPicLearnSync", params); return Service.Hades("public/knowledge/exportPicLearnSync", params);
} }
// 视频课观看记录导出 // 线上课观看记录导出
exportVideoLearnSync = (params: object) => { exportVideoLearnSync = (params: object) => {
return Service.Hades("public/knowledge/exportVideoLearnSync", params); return Service.Hades("public/knowledge/exportVideoLearnSync", params);
} }
......
/* /*
* @Author: zhangleyuan * @Author: zhangleyuan
* @Date: 2021-02-21 16:08:38 * @Date: 2021-02-21 16:08:38
* @LastEditors: zhangleyuan * @LastEditors: yuananting
* @LastEditTime: 2021-03-09 12:54:31 * @LastEditTime: 2021-07-06 11:26:27
* @Description: 描述一下 * @Description: 描述一下
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import Service from "@/common/js/service"; import Service from '@/common/js/service';
export function getTrainingPlanPage(params: object) { export function getTrainingPlanPage(params: object) {
return Service.Hades("public/hades/getTrainingPlanPage", params); return Service.Hades('public/hades/getTrainingPlanPage', params);
} }
export function createTrainingPlan(params: object) { export function createTrainingPlan(params: object) {
return Service.Hades("public/hades/createTrainingPlan", params); return Service.Hades('public/hades/createTrainingPlan', params);
} }
export function updateStateTrainingPlan(params: object) { export function updateStateTrainingPlan(params: object) {
return Service.Hades("public/hades/updateStateTrainingPlan", params); return Service.Hades('public/hades/updateStateTrainingPlan', params);
} }
export function getTrainingPlanDetail(params: object) { export function getTrainingPlanDetail(params: object) {
return Service.Hades("public/hades/getTrainingPlanDetail", params); return Service.Hades('public/hades/getTrainingPlanDetail', params);
} }
export function updateTrainingPlan(params: object) { export function updateTrainingPlan(params: object) {
return Service.Hades("public/hades/updateTrainingPlan", params); return Service.Hades('public/hades/updateTrainingPlan', params);
} }
export function deleteTrainingPlan(params: object) { export function deleteTrainingPlan(params: object) {
return Service.Hades("public/hades/deleteTrainingPlan", params); return Service.Hades('public/hades/deleteTrainingPlan', params);
} }
export function getPlanUserRecordPage(params: object) { export function getPlanUserRecordPage(params: object) {
return Service.Hades("public/hades/getPlanUserRecordPage", params); return Service.Hades('public/hades/getPlanUserRecordPage', params);
} }
export function getPlanCustomerRecordPage(params: object) { export function getPlanCustomerRecordPage(params: object) {
return Service.Hades("public/hades/getPlanCustomerRecordPage", params); return Service.Hades('public/hades/getPlanCustomerRecordPage', params);
} }
export function getPlanCustomerDetail(params: object) { export function getPlanCustomerDetail(params: object) {
return Service.Hades("public/hades/getPlanCustomerDetail", params); return Service.Hades('public/customerHades/getPlanCustomerDetail', params);
} }
export function getPlanCustomerAboutUser(params: object) { export function getPlanCustomerAboutUser(params: object) {
return Service.Hades("public/hades/getPlanCustomerAboutUser", params); return Service.Hades('public/hades/getPlanCustomerAboutUser', params);
} }
export function removePlanCustomer(params: object) { export function removePlanCustomer(params: object) {
return Service.Hades("public/hades/removePlanCustomer", params); return Service.Hades('public/hades/removePlanCustomer', params);
} }
export function getStorePlanAll(params: object) { export function getStorePlanAll(params: object) {
return Service.Hades("public/hades/getStorePlanAll", params); return Service.Hades('public/hades/getStorePlanAll', params);
} }
export function getTrainingCourseAutoCancel(params: object) { export function getTrainingCourseAutoCancel(params: object) {
return Service.Hades("public/hades/getTrainingCourseAutoCancel", params); return Service.Hades('public/hades/getTrainingCourseAutoCancel', params);
} }
/* /*
* @Author: yuananting * @Author: yuananting
* @Date: 2021-03-11 11:34:37 * @Date: 2021-03-11 11:34:37
* @LastEditors: fusanqiasng * @LastEditors: yuananting
* @LastEditTime: 2021-06-16 09:56:46 * @LastEditTime: 2021-07-09 16:54:54
* @Description: 助学工具接口 * @Description: 助学工具接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { import {
queryExternalCategoryTree, queryExternalCategoryTree,
queryCategoryTreeByPackage,
queryCategoryTree, queryCategoryTree,
addCategory, addCategory,
delCategory, delCategory,
...@@ -38,6 +39,11 @@ export default class AidToolService { ...@@ -38,6 +39,11 @@ export default class AidToolService {
return queryExternalCategoryTree(parmas); return queryExternalCategoryTree(parmas);
} }
// 课程分类树(按课程包)
static queryCategoryTreeByPackage(params: any) {
return queryCategoryTreeByPackage(params);
}
// 获取题目分类树 // 获取题目分类树
static queryCategoryTree(params: any) { static queryCategoryTree(params: any) {
return queryCategoryTree(params); return queryCategoryTree(params);
......
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
* @Author: wufan * @Author: wufan
* @Date: 2020-12-01 17:20:49 * @Date: 2020-12-01 17:20:49
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-25 11:02:06 * @LastEditTime: 2021-07-09 15:33:59
* @Description: Description * @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有 * @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import { getUserStore, getUserPermission ,logout,getStoreUser,sendBizAuthCode,editUserPhone,checkBizAuthCode,sendNewPhoneAuthCode,sendLoginAuthCode,login,getLastedVersion, getEnterpriseUser,getWXWorkLoginNoCheck,getLesseeVersionMsg,getYoZoSign,saveYoZoFileVersionId,yoZoUpload} from '@/data-source/base/request-apis'; import { getUserStore, getUserPermission ,logout,getStoreUser,sendBizAuthCode,editUserPhone,checkBizAuthCode,sendNewPhoneAuthCode,sendLoginAuthCode,login,getLastedVersion, getEnterpriseUser,getWXWorkLoginNoCheck,getLesseeVersionMsg,getYoZoSign,saveYoZoFileVersionId,yoZoUpload,saveFileVersionIdByCourseChapter} from '@/data-source/base/request-apis';
export default class StoreService { export default class StoreService {
// 获取员工列表 // 获取员工列表
...@@ -73,4 +73,7 @@ export default class StoreService { ...@@ -73,4 +73,7 @@ export default class StoreService {
static yoZoUpload(ossUrl:String,appId:String,uploadSign:String){ static yoZoUpload(ossUrl:String,appId:String,uploadSign:String){
return yoZoUpload(ossUrl,appId,uploadSign); return yoZoUpload(ossUrl,appId,uploadSign);
} }
static saveFileVersionIdByCourseChapter(params: any){
return saveFileVersionIdByCourseChapter(params);
}
} }
\ No newline at end of file
...@@ -9,7 +9,8 @@ ...@@ -9,7 +9,8 @@
import { import {
fetchLecturerData, getCategoryTree, knowledgeMediaCoursePage, 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,
lineDetailWatchInfo
} from '@/data-source/course/request-api'; } from '@/data-source/course/request-api';
export default class courseService { export default class courseService {
...@@ -85,6 +86,9 @@ export default class courseService { ...@@ -85,6 +86,9 @@ export default class courseService {
static videoWatchInfo(params: any) { static videoWatchInfo(params: any) {
return videoWatchInfo(params); return videoWatchInfo(params);
} }
static lineDetailWatchInfo(params: any) {
return lineDetailWatchInfo(params);
}
static getLiveCloudCourseBasePage(params: any) { static getLiveCloudCourseBasePage(params: any) {
return getLiveCloudCourseBasePage(params); return getLiveCloudCourseBasePage(params);
} }
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-24 12:20:57 * @Date: 2020-08-24 12:20:57
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-04 18:19:52 * @LastEditTime: 2021-07-08 19:38:52
* @Description: * @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
--> -->
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
/> />
<meta <meta
name="keywords" name="keywords"
content="小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,资料云盘,培训课程,培训任务,直播课,视频课,图文课,线下课,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂" content="小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,资料云盘,培训课程,培训任务,直播课,线上课,图文课,线下课,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂"
/> />
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> --> <!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png" /> <link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png" />
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div> <div id="root"></div>
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.
...@@ -63,166 +64,6 @@ ...@@ -63,166 +64,6 @@
To begin the development, run `npm start` or `yarn start`. To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`. To create a production bundle, use `npm run build` or `yarn build`.
--> -->
<script>
// (function (root, factory) {
// if (typeof define === 'function' && define.amd) {
// // AMD. Register as an anonymous module.
// define([], factory);
// } else if (typeof exports === 'object') {
// // Node. Does not work with strict CommonJS, but
// // only CommonJS-like environments that support module.exports,
// // like Node.
// module.exports = factory();
// } else {
// // Browser globals (root is window)
// root.download = factory();
// }
// })(this, function () {
// return function download(data, strFileName, strMimeType) {
// var self = window, // this script is only for browsers anyway...
// defaultMime = 'application/octet-stream', // this default mime also triggers iframe downloads
// mimeType = strMimeType || defaultMime,
// payload = data,
// url = !strFileName && !strMimeType && payload,
// anchor = document.createElement('a'),
// toString = function (a) {
// return String(a);
// },
// myBlob = self.Blob || self.MozBlob || self.WebKitBlob || toString,
// fileName = strFileName || 'download',
// blob,
// reader;
// myBlob = myBlob.call ? myBlob.bind(self) : Blob;
// if (String(this) === 'true') {
// //reverse arguments, allowing download.bind(true, "text/xml", "export.xml") to act as a callback
// payload = [payload, mimeType];
// mimeType = payload[0];
// payload = payload[1];
// }
// if (url && url.length < 2048) {
// // if no filename and no mime, assume a url was passed as the only argument
// fileName = url.split('/').pop().split('?')[0];
// anchor.href = url; // assign href prop to temp anchor
// if (anchor.href.indexOf(url) !== -1) {
// // if the browser determines that it's a potentially valid url path:
// var ajax = new XMLHttpRequest();
// ajax.open('GET', url, true);
// ajax.responseType = 'blob';
// ajax.onload = function (e) {
// download(e.target.response, fileName, defaultMime);
// };
// setTimeout(function () {
// ajax.send();
// }, 0); // allows setting custom ajax headers using the return:
// return ajax;
// } // end if valid url?
// } // end if url?
// //go ahead and download dataURLs right away
// if (/^data\:[\w+\-]+\/[\w+\-]+[,;]/.test(payload)) {
// if (payload.length > 1024 * 1024 * 1.999 && myBlob !== toString) {
// payload = dataUrlToBlob(payload);
// mimeType = payload.type || defaultMime;
// } else {
// return navigator.msSaveBlob // IE10 can't do a[download], only Blobs:
// ? navigator.msSaveBlob(dataUrlToBlob(payload), fileName)
// : saver(payload); // everyone else can save dataURLs un-processed
// }
// } //end if dataURL passed?
// blob = payload instanceof myBlob ? payload : new myBlob([payload], { type: mimeType });
// function dataUrlToBlob(strUrl) {
// var parts = strUrl.split(/[:;,]/),
// type = parts[1],
// decoder = parts[2] == 'base64' ? atob : decodeURIComponent,
// binData = decoder(parts.pop()),
// mx = binData.length,
// i = 0,
// uiArr = new Uint8Array(mx);
// for (i; i < mx; ++i) uiArr[i] = binData.charCodeAt(i);
// return new myBlob([uiArr], { type: type });
// }
// function saver(url, winMode) {
// if ('download' in anchor) {
// //html5 A[download]
// anchor.href = url;
// anchor.setAttribute('download', fileName);
// anchor.className = 'download-js-link';
// anchor.innerHTML = 'downloading...';
// anchor.style.display = 'none';
// document.body.appendChild(anchor);
// setTimeout(function () {
// anchor.click();
// document.body.removeChild(anchor);
// if (winMode === true) {
// setTimeout(function () {
// self.URL.revokeObjectURL(anchor.href);
// }, 250);
// }
// }, 66);
// return true;
// }
// // handle non-a[download] safari as best we can:
// if (/(Version)\/(\d+)\.(\d+)(?:\.(\d+))?.*Safari\//.test(navigator.userAgent)) {
// url = url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
// if (!window.open(url)) {
// // popup blocked, offer direct download:
// if (confirm('Displaying New Document\n\nUse Save As... to download, then click back to return to this page.')) {
// location.href = url;
// }
// }
// return true;
// }
// //do iframe dataURL download (old ch+FF):
// var f = document.createElement('iframe');
// document.body.appendChild(f);
// if (!winMode) {
// // force a mime that will download:
// url = 'data:' + url.replace(/^data:([\w\/\-\+]+)/, defaultMime);
// }
// f.src = url;
// setTimeout(function () {
// document.body.removeChild(f);
// }, 333);
// } //end saver
// if (navigator.msSaveBlob) {
// // IE10+ : (has Blob, but not a[download] or URL)
// return navigator.msSaveBlob(blob, fileName);
// }
// if (self.URL) {
// // simple fast and modern way using Blob and URL:
// saver(self.URL.createObjectURL(blob), true);
// } else {
// // handle non-Blob()+non-URL browsers:
// if (typeof blob === 'string' || blob.constructor === toString) {
// try {
// return saver('data:' + mimeType + ';base64,' + self.btoa(blob));
// } catch (y) {
// return saver('data:' + mimeType + ',' + encodeURIComponent(blob));
// }
// }
// // Blob but not URL support:
// reader = new FileReader();
// reader.onload = function (e) {
// saver(this.result);
// };
// reader.readAsDataURL(blob);
// }
// return true;
// }; /* end download() */
// });
</script>
</body> </body>
</html> </html>
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-04-27 20:35:34 * @Date: 2020-04-27 20:35:34
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-04 16:59:14 * @LastEditTime: 2021-07-08 19:22:18
* @Description: * @Description:
*/ */
......
...@@ -53,88 +53,12 @@ class CollegeInfoPage extends React.Component { ...@@ -53,88 +53,12 @@ class CollegeInfoPage extends React.Component {
}) })
} }
handleSelectCover = (file)=> { handleSelectCover = (file)=> {
// this.uploadImage(file);
this.setState({ this.setState({
visible: true, visible: true,
imageFile:file imageFile:file
}); });
} }
//上传图片
// uploadImage = (imageFile) => {
// const { folderName } = imageFile;
// const fileName = window.random_string(16) + folderName.slice(folderName.lastIndexOf("."));
// const self = this;
// this.setState(
// {
// visible: true,
// },
// () => {
// setTimeout(() => {
// const okBtnDom = document.querySelector("#headPicModal");
// const options = {
// size: [500, 128],
// ok: okBtnDom,
// maxZoom: 3,
// style: {
// jpgFillColor: "transparent",
// },
// done: function (dataUrl) {
// clearTimeout(self.timer);
// self.timer = setTimeout(() => {
// if ((self.state.rotate != this.rotate()) || (self.state.scale != this.scale())) {
// console.log(this.scale(), 'scale')
// const _dataUrl = this.clip()
// const cutImageBlob = self.convertBase64UrlToBlob(_dataUrl);
// self.setState({
// cutImageBlob,
// dataUrl: _dataUrl,
// rotate: this.rotate(),
// scale: this.scale()
// })
// }
// }, 500)
// const cutImageBlob = self.convertBase64UrlToBlob(dataUrl);
// self.setState({
// cutImageBlob,
// dataUrl
// })
// setTimeout(() => {
// cutFlag = false;
// }, 2000);
// },
// fail: (failInfo) => {
// message.error("图片上传失败了,请重新上传");
// },
// loadComplete: function (img) {
// setTimeout(() => {
// const _dataUrl = this.clip()
// self.setState({
// dataUrl: _dataUrl,
// hasImgReady: true
// })
// }, 100)
// },
// };
// const imgUrl = `${imageFile.ossUrl}?${new Date().getTime()}`
// if (!this.state.photoclip) {
// const _photoclip = new PhotoClip("#headPicModal", options);
// _photoclip.load(imgUrl);
// this.setState({
// photoclip: _photoclip,
// });
// } else {
// this.state.photoclip.clear();
// this.state.photoclip.load(imgUrl);
// }
// }, 200);
// }
// );
// };
//获取resourceId //获取resourceId
getSignature = (blob, fileName) => { getSignature = (blob, fileName) => {
...@@ -157,16 +81,6 @@ class CollegeInfoPage extends React.Component { ...@@ -157,16 +81,6 @@ class CollegeInfoPage extends React.Component {
}) })
} }
// base64转换成blob
// convertBase64UrlToBlob = (urlData) => {
// const bytes = window.atob(urlData.split(",")[1]);
// const ab = new ArrayBuffer(bytes.length);
// const ia = new Uint8Array(ab);
// for (let i = 0; i < bytes.length; i++) {
// ia[i] = bytes.charCodeAt(i);
// }
// return new Blob([ab], { type: "image/png" });
// };
updateInfo=()=>{ updateInfo=()=>{
const { storeName, logo } = this.state; const { storeName, logo } = this.state;
if(!storeName){ if(!storeName){
...@@ -197,9 +111,8 @@ class CollegeInfoPage extends React.Component { ...@@ -197,9 +111,8 @@ class CollegeInfoPage extends React.Component {
} = this.state; } = this.state;
return ( return (
<div className="page college-info-page"> <div className="page college-info-page">
<div className="content-header">学院基本信息</div> <div className="content-header">学院信息</div>
<div className="box"> <div className="box">
<div className="college-info-header">学院基本信息</div>
<div className="college-info-page-form"> <div className="college-info-page-form">
<Form ref={this.formRef}> <Form ref={this.formRef}>
...@@ -251,65 +164,6 @@ class CollegeInfoPage extends React.Component { ...@@ -251,65 +164,6 @@ class CollegeInfoPage extends React.Component {
onSelect={this.handleSelectCover} onSelect={this.handleSelectCover}
/> />
} }
{/* <Modal
title="设置图片"
width={1080}
visible={visible}
maskClosable={false}
closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
onCancel={() => {
this.setState({ visible: false });
}}
zIndex={10001}
footer={[
<Button
key="back"
onClick={() => {
this.setState({ visible: false });
}}
>
重新上传
</Button>,
<Button
key="submit"
type="primary"
disabled={!hasImgReady}
onClick={() => {
if (!cutFlag) {
cutFlag = true;
this.refs.hiddenBtn.click();
}
this.getSignature(cutImageBlob);
}}
>
确定
</Button>,
]}
>
<div className="clip-box">
<div
id="headPicModal"
ref="headPicModal"
style={{
width: "500px",
height: "430px",
marginBottom: 0,
}}
></div>
<div id="clipBtn" style={{ display: "none" }} ref="hiddenBtn"></div>
<div className="preview-img">
<div className="title">效果预览</div>
<div id="preview-url-box" style={{width:500,height:128}}>
<img src={this.state.dataUrl} style={{ width: '100%' }} alt="" />
</div>
<div className="tip-box">
<div className="tip">温馨提示</div>
<div className="tip">①预览效果图时可能存在延迟,单击左侧图片刷新即可</div>
<div className="tip">②设置图片时双击可旋转图片,滚动可放大或缩小图片</div>
</div>
</div>
</div>
</Modal> */}
{ visible && { visible &&
<ImgClipModal visible={visible} imgUrl={imageFile.ossUrl} aspectRatio='125/32' cropBoxHeight='128' onConfirm={this.getSignature} onClose={()=>{this.setState({ visible: false });}}/> <ImgClipModal visible={visible} imgUrl={imageFile.ossUrl} aspectRatio='125/32' cropBoxHeight='128' onConfirm={this.getSignature} onClose={()=>{this.setState({ visible: false });}}/>
} }
......
...@@ -2,41 +2,25 @@ ...@@ -2,41 +2,25 @@
.label { .label {
width: 100px; width: 100px;
text-align: right; text-align: right;
display:inline-block; display: inline-block;
.require { .require {
color: #EC4B35; color: #ec4b35;
} }
} }
.course-cover { .course-cover {
margin-left: 14px; margin-left: 14px;
display: flex; display: flex;
margin-top: 16px; margin-top: 24px;
&__wrap { &__wrap {
position: relative; position: relative;
.tag {
border-radius: 2px;
background: #D6D6D6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #FFF;
position: absolute;
top: 8px;
left: 8px;
}
}
.course-cover__wrap {
display: flex;
flex-direction: row;
}
.img-content { .img-content {
margin-top: 8px;
margin-right: 20px; margin-right: 20px;
width: 299px; width: 299px;
height: 169px; height: 169px;
position: relative;
img { img {
width: 100%; width: 100%;
...@@ -44,17 +28,28 @@ ...@@ -44,17 +28,28 @@
object-fit: contain; object-fit: contain;
border-radius: 4px; border-radius: 4px;
} }
.tag {
border-radius: 2px;
background: #d6d6d6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #fff;
position: absolute;
top: 8px;
left: 8px;
}
} }
.opt-btns { .opt-btns {
.default-btn { .default-btn {
margin-left: 16px; margin-left: 14px;
color: #2966FF; color: #2966ff;
cursor: pointer; cursor: pointer;
&.disabled { &.disabled {
color: #CCC; color: #ccc;
cursor: not-allowed; cursor: not-allowed;
} }
} }
...@@ -62,21 +57,21 @@ ...@@ -62,21 +57,21 @@
.ant-upload-list { .ant-upload-list {
display: none; display: none;
} }
}
.tips { .tips {
margin-top: 8px; margin-top: 8px;
color: #999; color: #999;
} }
} }
.course-catalog{
margin:20px 0 0 14px;
} }
}
.course-catalog {
margin: 20px 0 0 14px;
}
} }
.ant-cascader-menu-item-active:not(.ant-cascader-menu-item-disabled){ .ant-cascader-menu-item-active:not(.ant-cascader-menu-item-disabled) {
font-weight:normal !important; font-weight: normal !important;
color:#2966FF !important; color: #2966ff !important;
} }
#imgCutModalNew { #imgCutModalNew {
width: 500px; width: 500px;
...@@ -84,9 +79,4 @@ ...@@ -84,9 +79,4 @@
} }
.preview-url-box{ .preview-url-box{
overflow: hidden; overflow: hidden;
// img{
// width:500px !important;
// height:282px !important;
// transform:none !important;
// }
} }
.graphics-editor-container { .graphics-editor-container {
border: 1px solid #E8E8E8; border: 1px solid #e8e8e8;
border-radius: 4px; border-radius: 4px;
width: 702px; width: 702px;
height: 510px; height: 510px;
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.w-e-toolbar { .w-e-toolbar {
background-color: #fff !important; background-color: #fff !important;
border: none !important; border: none !important;
border-bottom: 1px solid #E8E8E8 !important; border-bottom: 1px solid #e8e8e8 !important;
} }
.w-e-text-container { .w-e-text-container {
...@@ -38,19 +38,26 @@ ...@@ -38,19 +38,26 @@
color: #666; color: #666;
z-index: 1; z-index: 1;
} }
.editor-warning {
position: absolute;
right: 0;
color: red;
}
.w-e-full-screen-editor { .w-e-full-screen-editor {
.w-e-text-container { .w-e-text-container {
height: ~'calc(100vh - 109px)' !important; height: ~'calc(100vh - 109px)' !important;
} }
} }
&.introduce { &.introduce {
height: 200px; height: 240px;
.w-e-text-container { .w-e-text-container {
height: ~'calc(100% - 69px)' !important; height: ~'calc(100% - 69px)' !important;
} }
} }
&.warning{ &.warning {
border-color: red; border-color: red;
} }
} }
.live-course-list { .live-course-list {
margin-top: 12px; margin-top: 12px;
.record__item { .record__item {
overflow: hidden;
display: flex; display: flex;
align-items: center; align-items: center;
.course-cover { .course-cover {
...@@ -11,63 +11,61 @@ ...@@ -11,63 +11,61 @@
border-radius: 2px; border-radius: 2px;
margin-right: 8px; margin-right: 8px;
} }
.course-name{ .course-name {
font-size: 14px; font-size: 14px;
font-weight: 500; font-weight: 500;
color: #333333; color: #333333;
line-height: 20px; line-height: 20px;
font-weight: bold; font-weight: bold;
max-width:244px; max-width: 200px;
overflow: hidden; overflow: hidden;
text-overflow:ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.course-time{ .course-time {
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
color: #666666; color: #666666;
line-height: 20px; line-height: 20px;
} }
.course-status { .course-status {
font-size:12px; font-size: 12px;
line-height:18px; line-height: 18px;
display:inline-block; display: inline-block;
border-radius:2px; border-radius: 2px;
padding:0 8px; padding: 0 8px;
margin-left:4px; margin-left: 4px;
} }
.teacher-assistant{ .teacher-assistant {
display:flex; display: flex;
.teacher{ .teacher {
font-size: 12px; font-size: 12px;
color: #666666; color: #666666;
max-width: 96px; max-width: 96px;
overflow: hidden; overflow: hidden;
text-overflow:ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
display:inline-block; display: inline-block;
padding-top:2px; padding-top: 2px;
} }
.assistant{ .assistant {
font-size: 12px; font-size: 12px;
color: #666666; color: #666666;
max-width: 96px; max-width: 96px;
overflow: hidden; overflow: hidden;
text-overflow:ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
display:inline-block; display: inline-block;
padding-top:2px; padding-top: 2px;
} }
.split { .split {
margin: 0 4px; margin: 0 4px;
color: #BFBFBF; color: #bfbfbf;
display: inline-blcok; display: inline-blcok;
} }
} }
} }
.related-task{ .related-task {
text-overflow: -o-ellipsis-lastline; text-overflow: -o-ellipsis-lastline;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
...@@ -76,37 +74,37 @@ ...@@ -76,37 +74,37 @@
line-clamp: 2; line-clamp: 2;
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
} }
.categoryName{ .categoryName {
font-size: 14px; font-size: 14px;
color: #666666; color: #666666;
line-height: 20px; line-height: 20px;
} }
.courseware{ .courseware {
font-size: 14px; font-size: 14px;
color: #2966FF; color: #2966ff;
line-height: 20px; line-height: 20px;
text-align:right; text-align: right;
cursor:pointer; cursor: pointer;
} }
.quota-icon{ .quota-icon {
color:#2966FF; color: #2966ff;
cursor:pointer; cursor: pointer;
} }
.operate { .operate {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: wrap; flex-wrap: wrap;
.operate__item { .operate__item {
color: #2966FF; color: #2966ff;
cursor: pointer; cursor: pointer;
&.split { &.split {
margin: 0 8px; margin: 0 8px;
color: #BFBFBF; color: #bfbfbf;
} }
} }
} }
.operate-text { .operate-text {
color: #2966FF; color: #2966ff;
cursor: pointer; cursor: pointer;
} }
.course-start-end { .course-start-end {
...@@ -135,7 +133,27 @@ ...@@ -135,7 +133,27 @@
font-size: 12px; font-size: 12px;
} }
} }
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;
}
}
}
}
} }
.live-course-more-menu { .live-course-more-menu {
background: white; background: white;
......
...@@ -63,8 +63,7 @@ class LiveCourseOpt extends React.Component { ...@@ -63,8 +63,7 @@ class LiveCourseOpt extends React.Component {
{ userRole !== "CloudLecturer" && { userRole !== "CloudLecturer" &&
<Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button> <Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button>
} }
<Button type="primary" onClick={this.handleCreateQWCouese}>新建企微直播课</Button> <Button onClick={this.handleDownloadClient}>下载直播客户端</Button>
{!this.state.isMac && <Button onClick={this.handleDownloadClient}>下载直播客户端</Button>}
</div> </div>
<Route path={`${match.url}/createqwcourse`} component={CerateQWCourse} /> <Route path={`${match.url}/createqwcourse`} component={CerateQWCourse} />
</div> </div>
......
.add-graphics-course-page { .add-graphics-course-page {
position:relative !important; position: relative !important;
.box{ .box {
margin-bottom:52px !important; margin-bottom: 52px !important;
} }
.ant-radio-group { .ant-radio-group {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.radio-item { .radio-item {
margin-bottom: 12px; margin-bottom: 12px;
...@@ -28,10 +27,10 @@ ...@@ -28,10 +27,10 @@
.form { .form {
margin-top: 16px; margin-top: 16px;
padding: 0 16px; padding: 0 16px;
.label{ .label {
display:inline-block; display: inline-block;
text-align:right; text-align: right;
width:85px; width: 85px;
} }
.required { .required {
position: relative; position: relative;
...@@ -48,9 +47,9 @@ ...@@ -48,9 +47,9 @@
top: 0; top: 0;
} }
} }
.course-catalog{ .course-catalog {
margin-bottom:16px; margin-bottom: 16px;
margin-top:16px; margin-top: 16px;
} }
.course-ware { .course-ware {
display: flex; display: flex;
...@@ -71,10 +70,20 @@ ...@@ -71,10 +70,20 @@
display: flex; display: flex;
} }
.cover-url__wrap { .course-cover {
margin-left: 14px;
display: flex;
margin-top: 24px;
&__wrap {
position: relative;
.img-content { .img-content {
width: 298px; margin-top: 8px;
height: 172px; margin-right: 20px;
width: 299px;
height: 169px;
position: relative;
img { img {
width: 100%; width: 100%;
...@@ -82,29 +91,78 @@ ...@@ -82,29 +91,78 @@
object-fit: contain; object-fit: contain;
border-radius: 4px; border-radius: 4px;
} }
} .tag {
.empty-img { border-radius: 2px;
width: 298px; background: #d6d6d6;
height: 172px; font-size: 12px;
border: 1px dashed #EBEBEB; height: 18px;
border-radius: 4px; width: 52px;
padding: 12px;
color: #999;
padding: 52px 24px;
text-align: center; text-align: center;
color: #fff;
position: absolute;
top: 8px;
left: 8px;
}
} }
.opt-btns { .opt-btns {
margin-top: 8px; .default-btn {
display: flex; margin-left: 14px;
align-items: center; color: #2966ff;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
}
}
.ant-upload-list {
display: none;
}
.tips { .tips {
margin-left: 12px; margin-top: 8px;
color: #999; color: #999;
} }
} }
} }
}
// .cover-url__wrap {
// .img-content {
// width: 298px;
// height: 172px;
// img {
// width: 100%;
// height: 100%;
// object-fit: contain;
// border-radius: 4px;
// }
// }
// .empty-img {
// width: 298px;
// height: 172px;
// border: 1px dashed #EBEBEB;
// border-radius: 4px;
// padding: 12px;
// color: #999;
// padding: 52px 24px;
// text-align: center;
// }
// .opt-btns {
// margin-top: 8px;
// display: flex;
// align-items: center;
// .tips {
// margin-left: 12px;
// color: #999;
// }
// }
// }
.select-student { .select-student {
align-items: center; align-items: center;
...@@ -139,7 +197,7 @@ ...@@ -139,7 +197,7 @@
justify-content: flex-end; justify-content: flex-end;
padding-right: 72px; padding-right: 72px;
background: #fff; background: #fff;
border-top: 1px solid #E8E8E8; border-top: 1px solid #e8e8e8;
z-index: 999; z-index: 999;
.ant-btn { .ant-btn {
margin-left: 10px; margin-left: 10px;
......
...@@ -17,17 +17,15 @@ import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepare ...@@ -17,17 +17,15 @@ import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepare
import { DISK_MAP } from '@/common/constants/academic/lessonEnum'; import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components'; import { ImgCutModalNew } from '@/components';
const { TextArea } = Input; const { TextArea } = Input;
class AddGraphicsIntro extends React.Component { class AddGraphicsIntro extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
showSelectFileModal: false, showSelectFileModal: false,
diskList: [], diskList: [],
selectType: null, selectType: null,
} };
} }
// 上传封面图 // 上传封面图
...@@ -38,34 +36,34 @@ class AddGraphicsIntro extends React.Component { ...@@ -38,34 +36,34 @@ class AddGraphicsIntro extends React.Component {
imageFile, imageFile,
showCutModal: true, showCutModal: true,
}); });
} };
// 选择暖场资源 // 选择暖场资源
handleSelectVideo = (file) => { handleSelectVideo = (file) => {
const { selectType } = this.state; const { selectType } = this.state;
this.setState({ this.setState({
showSelectFileModal: false showSelectFileModal: false,
}) });
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file; const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){ if (selectType === 'WARMUP') {
const liveCourseWarmMedia = { const liveCourseWarmMedia = {
contentType: 'WARMUP', contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE', mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId, mediaContent: resourceId,
mediaUrl: ossUrl, mediaUrl: ossUrl,
mediaName: folderName, mediaName: folderName,
size: folderSize size: folderSize,
} };
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia); this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{ } else {
// 最多添加九图片 // 最多添加九图片
const { liveCourseMediaRequests } = this.props.data; const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => { const list = _.filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE"; return item.mediaType == 'PICTURE';
}); });
if (list.length > 8) { if (list.length > 8) {
message.warning("最多添加9张图片"); message.warning('最多添加9张图片');
return; return;
} }
liveCourseMediaRequests.push({ liveCourseMediaRequests.push({
...@@ -78,121 +76,116 @@ class AddGraphicsIntro extends React.Component { ...@@ -78,121 +76,116 @@ class AddGraphicsIntro extends React.Component {
}); });
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests); this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
} }
};
}
changeDetail = (value) => { changeDetail = (value) => {
this.props.onChange('courseMedia', value); this.props.onChange('courseMedia', value);
} };
changeIntro = (value) => { changeIntro = (value) => {
this.props.onChange('introduce', value); this.props.onChange('introduce', value);
} };
whetherVisitorsJoinChange = ()=>{ whetherVisitorsJoinChange = () => {
if(this.props.data.whetherVisitorsJoin==="NO"){ if (this.props.data.whetherVisitorsJoin === 'NO') {
this.props.onChange('whetherVisitorsJoin','YES') this.props.onChange('whetherVisitorsJoin', 'YES');
}else{ } else {
this.props.onChange('whetherVisitorsJoin','NO') this.props.onChange('whetherVisitorsJoin', 'NO');
}
} }
};
shelfStateChange = ()=>{ shelfStateChange = () => {
if(this.props.data.shelfState==="NO"){ if (this.props.data.shelfState === 'NO') {
this.props.onChange('shelfState','YES') this.props.onChange('shelfState', 'YES');
}else{ } else {
this.props.onChange('shelfState','NO') this.props.onChange('shelfState', 'NO');
}
} }
};
render() { render() {
const {data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce } } = this.props; const {
data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce },
} = this.props;
const { showSelectFileModal, selectType } = this.state; const { showSelectFileModal, selectType } = this.state;
return ( return (
<div className="add-video__intro-info"> <div className='add-graphic__intro-info'>
<div className="allow-tourist-join"> <div className='allow-tourist-join'>
<span className="label">观看设置:</span> <span className='label'>观看设置:</span>
<div className="content"> <div className='content'>
<div> <Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} />
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/> <div className='desc'>{whetherVisitorsJoin === 'NO' ? '已开启,学员需绑定手机号才可观看' : '已关闭,学员无需绑定手机号即可观看'}</div>
</div> </div>
<div> </div>
<div className="desc"> <div className='store-show'>
<div>开启:允许未绑定手机号的学员观看</div> <span className='label'>学院展示:</span>
<div>关闭:仅限绑定了手机号的学员可以进入观看图文课</div> <div className='content'>
</div> <Switch checked={shelfState === 'YES' ? true : false} onChange={this.shelfStateChange} />
</div> <div className='desc'>{shelfState === 'YES' ? '已开启,课程将在该学院的学员课程列表中显示' : '已关闭,课程将在该学院的学员课程列表中隐藏'}</div>
</div> </div>
</div> </div>
<div className="store-show"> <div className='introduce required'>
<span className="label">学院展示:</span> <span className='label' style={{ marginTop: 5 }}>
<div className="content"> 课程内容:
<Row> </span>
<Col span={3}> <div className='content'>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/> <div className='intro-list'>
</Col> <div className='intro-list__item content-editor'>
<Col span={21}> {(!id || loadcourseMedia) && (
<div className="desc">
<div>开启:图文课将在学员学院图文课列表中展示</div>
<div>关闭:图文课将在学员学院图文课列表中隐藏</div>
</div>
</Col>
</Row>
</div>
</div>
<div className="introduce required">
<span className="label" style={{ marginTop: 5 }}>课程内容:</span>
<div className="content">
<div className="intro-list">
<div className="intro-list__item content-editor">
{(!id || loadcourseMedia) &&
<GraphicsEditor <GraphicsEditor
id="content" id='content'
maxLimit={1000}
editorType={'graphicsCourseContent'}
detail={{ detail={{
content: courseMedia content: courseMedia,
}}
onChange={(val) => {
this.changeDetail(val);
}} }}
onChange={(val) => { this.changeDetail(val) }}
/> />
} )}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="introduce"> <div className='introduce'>
<span className="label">课程简介:</span> <span className='label'>课程简介:</span>
<div className="content"> <div className='content'>
<div className="intro-list"> <div className='intro-list'>
<div className="intro-list__item introduce-editor"> <div className='intro-list__item introduce-editor'>
{(!id || loadintroduce) && {(!id || loadintroduce) && (
<GraphicsEditor <GraphicsEditor
id="intro" id='intro'
isIntro={true} isIntro={true}
maxLimit={1000}
editorType={'graphicsCourseIntor'}
detail={{ detail={{
content: introduce content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}} }}
onChange={(val) => { this.changeIntro(val) }}
/> />
} )}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* 选择暖场图文件弹窗 */} {/* 选择暖场图文件弹窗 */}
{ showSelectFileModal && {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
operateType="select" operateType='select'
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"} accept={selectType === 'INTRO' ? 'image/jpeg,image/png,image/jpg' : 'video/mp4,image/jpeg,image/png,image/jpg'}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] } selectTypeList={selectType === 'INTRO' ? ['JPG', 'JPEG', 'PNG'] : ['MP4', 'JPG', 'JPEG', 'PNG']}
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'} tooltip={selectType === 'INTRO' ? '支持文件类型:jpg、jpeg、png' : '支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal} isOpen={showSelectFileModal}
onClose={() => { onClose={() => {
this.setState({ showSelectFileModal: false }) this.setState({ showSelectFileModal: false });
}} }}
onSelect={this.handleSelectVideo} onSelect={this.handleSelectVideo}
/> />
} )}
</div> </div>
) );
} }
} }
......
.add-video__intro-info { .add-graphic__intro-info {
.w-e-full-screen-editor { .w-e-full-screen-editor {
background: #fff !important; background: #fff !important;
} }
.playback { .playback {
margin-bottom: 10px; margin-bottom: 10px;
.require { .require {
color: #EC4B35; color: #ec4b35;
} }
&__text { &__text {
color: #999; color: #999;
} }
} }
.label{ .label {
display:inline-block; display: inline-block;
text-align:right; text-align: right;
width:85px; width: 85px;
} }
.playback, .playback,
.introduce { .introduce {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
} }
.allow-tourist-join{ .allow-tourist-join {
display:flex; display: flex;
.content{ .content {
display:flex; display: flex;
} }
.desc{ .desc {
margin-left:16px; margin-left: 16px;
font-size:14px; font-size: 14px;
color:#999; color: #999;
display:inline-block; display: inline-block;
} }
} }
.store-show{ .store-show {
display:flex; display: flex;
margin-top:16px; margin-top: 16px;
margin-bottom:16px; margin-bottom: 16px;
.desc{ .content {
margin-left:16px; display: flex;
font-size:14px; }
color:#999; .desc {
display:inline-block; margin-left: 16px;
font-size: 14px;
color: #999;
display: inline-block;
} }
} }
.radio { .radio {
...@@ -59,13 +62,13 @@ ...@@ -59,13 +62,13 @@
.intro-list__item { .intro-list__item {
display: flex; display: flex;
margin-bottom: 16px; margin-bottom: 32px;
position: relative; position: relative;
&.picture { &.picture {
width: 550px; width: 550px;
padding: 16px; padding: 16px;
border: 1px solid #EEE; border: 1px solid #eee;
border-radius: 4px; border-radius: 4px;
.img__wrap { .img__wrap {
...@@ -114,7 +117,7 @@ ...@@ -114,7 +117,7 @@
line-height: 80px; line-height: 80px;
padding: 16px; padding: 16px;
margin-top: 16px; margin-top: 16px;
border: 1px dashed #EBEBEB; border: 1px dashed #ebebeb;
border-radius: 4px; border-radius: 4px;
.ant-upload { .ant-upload {
...@@ -133,7 +136,7 @@ ...@@ -133,7 +136,7 @@
.iconfont { .iconfont {
font-size: 22px; font-size: 22px;
line-height: 22px; line-height: 22px;
color: #BFBFBF; color: #bfbfbf;
text-align: center; text-align: center;
} }
...@@ -152,7 +155,7 @@ ...@@ -152,7 +155,7 @@
} }
.checkExample { .checkExample {
width: 60px; width: 60px;
color: #FF7519; color: #ff7519;
cursor: pointer; cursor: pointer;
} }
.warmup { .warmup {
...@@ -197,21 +200,19 @@ ...@@ -197,21 +200,19 @@
} }
} }
.opt-btns { .opt-btns {
.default-btn { .default-btn {
margin-left: 16px; margin-left: 16px;
color: #FF7519; color: #ff7519;
cursor: pointer; cursor: pointer;
&.disabled { &.disabled {
color: #CCC; color: #ccc;
cursor: not-allowed; cursor: not-allowed;
} }
} }
} }
}
} .example-wrap {
.example-wrap {
font-family: PingFangSC-Regular, PingFang SC; font-family: PingFangSC-Regular, PingFang SC;
text-align: center; text-align: center;
.title { .title {
...@@ -227,14 +228,14 @@ ...@@ -227,14 +228,14 @@
img { img {
width: 180px; width: 180px;
} }
} }
.check-record-rule { .check-record-rule {
width: 120px; width: 120px;
color: #FF7519; color: #ff7519;
cursor: pointer; cursor: pointer;
z-index: 2; z-index: 2;
} }
.record-rule-wrap { .record-rule-wrap {
text-align: left; text-align: left;
ul { ul {
margin-top: 10px; margin-top: 10px;
...@@ -247,9 +248,9 @@ ...@@ -247,9 +248,9 @@
.text { .text {
color: #999; color: #999;
} }
} }
.auto-send-class-report { .auto-send-class-report {
.label { .label {
width: 57px; width: 57px;
height: 12px; height: 12px;
...@@ -258,7 +259,8 @@ ...@@ -258,7 +259,8 @@
color: #666666; color: #666666;
line-height: 12px; line-height: 12px;
} }
.open-text, .close-text { .open-text,
.close-text {
width: 572px; width: 572px;
font-size: 14px; font-size: 14px;
font-weight: 400; font-weight: 400;
...@@ -273,4 +275,4 @@ ...@@ -273,4 +275,4 @@
.close-text { .close-text {
margin-bottom: 16px; margin-bottom: 16px;
} }
} }
\ No newline at end of file
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:12:45 * @Date: 2020-08-05 10:12:45
* @LastEditors: Please set LastEditors * @LastEditors: wufan
* @LastEditTime: 2021-06-21 11:24:29 * @LastEditTime: 2021-07-05 10:23:10
* @Description: 视频课-列表模块 * @Description: 线上课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import User from '@/common/js/user'; import User from '@/common/js/user';
import college from '@/common/lottie/college'; import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components'; import { PageControl, XMTable } from '@/components';
import { appId, LIVE_SHARE } from '@/domains/course-domain/constants'; import { LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService'; import CourseService from '@/domains/course-domain/CourseService';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal'; import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd'; import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
...@@ -57,7 +57,7 @@ class GraphicsCourseList extends React.Component { ...@@ -57,7 +57,7 @@ class GraphicsCourseList extends React.Component {
handlePlanName = (planArray) => { handlePlanName = (planArray) => {
let planStr = ''; let planStr = '';
planArray.map((item, index) => { planArray.forEach((item, index) => {
if (index < planArray.length - 1) { if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、'; planStr = planStr + item.planName + '、';
} else { } else {
...@@ -76,18 +76,21 @@ class GraphicsCourseList extends React.Component { ...@@ -76,18 +76,21 @@ class GraphicsCourseList extends React.Component {
width: 321, width: 321,
fixed: 'left', fixed: 'left',
render: (val, record) => { render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record; const { coverUrl } = record;
return ( return (
<div className='record__item'> <div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className='course-cover' src={coverUrl || defaultCoverUrl} /> <img className='course-cover' src={coverUrl || defaultCoverUrl} alt='' />
{record.courseName.length > 25 ? ( <Choose>
<When condition={record.courseName.length > 25}>
<Tooltip title={record.courseName}> <Tooltip title={record.courseName}>
<div className='course-name'>{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
</Tooltip> </Tooltip>
) : ( </When>
<Otherwise>
<div className='course-name'>{record.courseName}</div> <div className='course-name'>{record.courseName}</div>
)} </Otherwise>
</Choose>
</div> </div>
); );
}, },
...@@ -146,6 +149,7 @@ class GraphicsCourseList extends React.Component { ...@@ -146,6 +149,7 @@ class GraphicsCourseList extends React.Component {
render: (val, item, index) => { render: (val, item, index) => {
return ( return (
<Switch <Switch
size='small'
checked={item.shelfState === 'YES'} checked={item.shelfState === 'YES'}
defaultChecked={item.shelfState === 'YES' ? true : false} defaultChecked={item.shelfState === 'YES' ? true : false}
onChange={(checked) => this.changeShelfState(index, item, checked)} onChange={(checked) => this.changeShelfState(index, item, checked)}
...@@ -169,7 +173,7 @@ class GraphicsCourseList extends React.Component { ...@@ -169,7 +173,7 @@ class GraphicsCourseList extends React.Component {
dataIndex: 'created', dataIndex: 'created',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val); return window.formatDate('YYYY-MM-DD H:i', val);
}, },
}, },
{ {
...@@ -179,7 +183,7 @@ class GraphicsCourseList extends React.Component { ...@@ -179,7 +183,7 @@ class GraphicsCourseList extends React.Component {
dataIndex: 'updated', dataIndex: 'updated',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val); return window.formatDate('YYYY-MM-DD H:i', val);
}, },
}, },
{ {
...@@ -190,7 +194,8 @@ class GraphicsCourseList extends React.Component { ...@@ -190,7 +194,8 @@ class GraphicsCourseList extends React.Component {
render: (val, record) => { render: (val, record) => {
return ( return (
<div className='related-task'> <div className='related-task'>
{record.relatedPlanList ? ( <Choose>
<When condition={record.relatedPlanList}>
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter> <Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => { {record.relatedPlanList.map((item, index) => {
return ( return (
...@@ -200,9 +205,11 @@ class GraphicsCourseList extends React.Component { ...@@ -200,9 +205,11 @@ class GraphicsCourseList extends React.Component {
); );
})} })}
</Tooltip> </Tooltip>
) : ( </When>
<Otherwise>
<span></span> <span></span>
)} </Otherwise>
</Choose>
</div> </div>
); );
}, },
...@@ -298,7 +305,7 @@ class GraphicsCourseList extends React.Component { ...@@ -298,7 +305,7 @@ class GraphicsCourseList extends React.Component {
className='operate__item' className='operate__item'
key='edit' key='edit'
onClick={() => { onClick={() => {
RCHistory.push(`/create-graphics-course?type=edit&id=${item.id}`); window.RCHistory.push(`/create-graphics-course?type=edit&id=${item.id}`);
}}> }}>
编辑 编辑
</div> </div>
...@@ -334,7 +341,7 @@ class GraphicsCourseList extends React.Component { ...@@ -334,7 +341,7 @@ class GraphicsCourseList extends React.Component {
// 删除视频课 // 删除视频课
handleDeleteGraphicsCourse = (scheduleId) => { handleDeleteGraphicsCourse = (scheduleId) => {
Modal.confirm({ Modal.confirm({
title: '你确定要删除此视频课吗?', title: '你确定要删除此线上课吗?',
content: '删除后,学员将不能进行观看。', content: '删除后,学员将不能进行观看。',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>, icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
okText: '确定', okText: '确定',
...@@ -356,8 +363,6 @@ class GraphicsCourseList extends React.Component { ...@@ -356,8 +363,6 @@ class GraphicsCourseList extends React.Component {
// 显示分享弹窗 // 显示分享弹窗
handleShowShareModal = (record, needStr = false) => { handleShowShareModal = (record, needStr = false) => {
const { id, scheduleVideoUrl } = record; const { id, scheduleVideoUrl } = record;
const _appId = appId;
const htmlUrl = `${LIVE_SHARE}graphics_detail/${id}?id=${User.getStoreId()}`; const htmlUrl = `${LIVE_SHARE}graphics_detail/${id}?id=${User.getStoreId()}`;
const longUrl = htmlUrl; const longUrl = htmlUrl;
const { coverUrl, courseName } = record; const { coverUrl, courseName } = record;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* @Date: 2020-08-05 10:12:15 * @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 16:07:27 * @LastEditTime: 2020-12-26 16:07:27
* @Description: 视频课-操作模块 * @Description: 线上课-操作模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
......
...@@ -17,13 +17,13 @@ class GraphicsCourse extends React.Component { ...@@ -17,13 +17,13 @@ class GraphicsCourse extends React.Component {
courseType: 'PICTURE', courseType: 'PICTURE',
storeId:User.getStoreId() storeId:User.getStoreId()
}, },
dataSource: [], // 视频课列表 dataSource: [], // 线上课列表
totalCount: 0, // 视频课数据总条数 totalCount: 0, // 线上课数据总条数
} }
} }
componentWillMount() { componentWillMount() {
// 获取视频课列表 // 获取线上课列表
this.handleFetchScheduleList(); this.handleFetchScheduleList();
} }
...@@ -76,7 +76,7 @@ class GraphicsCourse extends React.Component { ...@@ -76,7 +76,7 @@ class GraphicsCourse extends React.Component {
{/* 操作模块 */} {/* 操作模块 */}
<GraphicsCourseOpt /> <GraphicsCourseOpt />
{/* 视频课列表模块 */} {/* 线上课列表模块 */}
<GraphicsCourseList <GraphicsCourseList
query={query} query={query}
dataSource={dataSource} dataSource={dataSource}
......
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
} }
.container { .container {
overflow: scroll; overflow-y: auto;
overflow-x: hidden;
height: 100%;; height: 100%;;
.course-cover, .course-url { .course-cover, .course-url {
...@@ -30,6 +31,16 @@ ...@@ -30,6 +31,16 @@
color: #000; color: #000;
} }
.title__category {
color: #999999;
margin-top: 4px;
margin-bottom: 4px;
}
.title__chapter {
color: #999999;
margin-bottom: 4px;
}
.title__inst-name { .title__inst-name {
color: #666; color: #666;
font-size: 12px; font-size: 12px;
......
...@@ -116,11 +116,7 @@ class ShareLiveModal extends React.Component { ...@@ -116,11 +116,7 @@ class ShareLiveModal extends React.Component {
} }
break; break;
case 'videoClass': // 视频课 case 'videoClass': // 视频课
coverImgSrc = coverImgSrc = coverUrl || 'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png';
coverUrl ||
(courseDivision === 'internal'
? `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring`
: 'https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png');
break; break;
case 'graphicsClass': // 图文课 case 'graphicsClass': // 图文课
coverImgSrc = coverUrl || 'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'; coverImgSrc = coverUrl || 'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png';
......
.add-offline-course-page { .add-offline-course-page {
position:relative !important; position: relative !important;
.box{ .box {
margin-bottom:52px !important; margin-bottom: 52px !important;
} }
.ant-radio-group { .ant-radio-group {
display: flex; display: flex;
...@@ -39,18 +39,18 @@ ...@@ -39,18 +39,18 @@
position: relative; position: relative;
padding-left: 14px; padding-left: 14px;
&::before { &::before {
content: ""; content: '';
position: absolute; position: absolute;
left: 0px; left: 0px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
width: 4px; width: 4px;
height: 10px; height: 10px;
background: #2966FF; background: #2966ff;
} }
} }
} }
.label{ .label {
display: inline-block; display: inline-block;
text-align: right; text-align: right;
width: 120px; width: 120px;
...@@ -75,8 +75,8 @@ ...@@ -75,8 +75,8 @@
} }
} }
.course-catalog { .course-catalog {
margin-bottom:16px; margin-bottom: 16px;
margin-top:16px; margin-top: 16px;
display: flex; display: flex;
.switch-box { .switch-box {
.switch-item { .switch-item {
...@@ -110,19 +110,19 @@ ...@@ -110,19 +110,19 @@
.select-day { .select-day {
margin-bottom: 4px; margin-bottom: 4px;
.mark-day { .mark-day {
color: #2966FF; color: #2966ff;
} }
} }
} }
.allow-tourist-join{ .allow-tourist-join {
display:flex; display: flex;
margin-bottom:16px; margin-bottom: 16px;
.desc { .desc {
color:#999; color: #999;
margin-left:12px; margin-left: 12px;
} }
.content{ .content {
display:flex; display: flex;
} }
} }
.course-ware { .course-ware {
...@@ -150,45 +150,41 @@ ...@@ -150,45 +150,41 @@
&__wrap { &__wrap {
position: relative; position: relative;
.tag {
border-radius: 2px;
background: #D6D6D6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #FFF;
position: absolute;
top: 8px;
left: 8px;
}
}
.course-cover__wrap {
display: flex;
flex-direction: row;
}
.img-content { .img-content {
margin-top: 8px;
margin-right: 20px; margin-right: 20px;
width: 299px; width: 299px;
height: 169px; height: 169px;
position: relative;
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
object-fit: contain; object-fit: contain;
border-radius: 4px;
}
.tag {
border-radius: 2px;
background: #d6d6d6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #fff;
position: absolute;
top: 8px;
left: 8px;
} }
} }
.opt-btns { .opt-btns {
.default-btn { .default-btn {
margin-left: 16px; margin-left: 14px;
color: #2966FF; color: #2966ff;
cursor: pointer; cursor: pointer;
&.disabled { &.disabled {
color: #CCC; color: #ccc;
cursor: not-allowed; cursor: not-allowed;
} }
} }
...@@ -196,13 +192,14 @@ ...@@ -196,13 +192,14 @@
.ant-upload-list { .ant-upload-list {
display: none; display: none;
} }
}
.tips { .tips {
margin-top: 8px; margin-top: 8px;
color: #999; color: #999;
} }
} }
}
}
.select-student { .select-student {
align-items: center; align-items: center;
...@@ -236,7 +233,7 @@ ...@@ -236,7 +233,7 @@
justify-content: flex-end; justify-content: flex-end;
padding-right: 72px; padding-right: 72px;
background: #fff; background: #fff;
border-top: 1px solid #E8E8E8; border-top: 1px solid #e8e8e8;
z-index: 999; z-index: 999;
.ant-btn { .ant-btn {
margin-left: 10px; margin-left: 10px;
......
...@@ -6,28 +6,20 @@ ...@@ -6,28 +6,20 @@
* @Description: 添加直播-简介 * @Description: 添加直播-简介
*/ */
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { Col, message, Row, Switch } from 'antd';
import React from 'react'; import React from 'react';
import { Input, message, Upload, Radio, Row, Col, Button, Popover, Switch } from 'antd';
import Service from '@/common/js/service';
import GraphicsEditor from '../../components/GraphicsEditor'; import GraphicsEditor from '../../components/GraphicsEditor';
import User from '@/common/js/user';
import UploadOss from '@/core/upload';
import './AddGraphicsIntro.less'; import './AddGraphicsIntro.less';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components';
const { TextArea } = Input;
class AddGraphicsIntro extends React.Component { class AddGraphicsIntro extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
showSelectFileModal: false, showSelectFileModal: false,
diskList: [], diskList: [],
selectType: null, selectType: null,
} };
} }
// 上传封面图 // 上传封面图
...@@ -38,34 +30,34 @@ class AddGraphicsIntro extends React.Component { ...@@ -38,34 +30,34 @@ class AddGraphicsIntro extends React.Component {
imageFile, imageFile,
showCutModal: true, showCutModal: true,
}); });
} };
// 选择暖场资源 // 选择暖场资源
handleSelectVideo = (file) => { handleSelectVideo = (file) => {
const { selectType } = this.state; const { selectType } = this.state;
this.setState({ this.setState({
showSelectFileModal: false showSelectFileModal: false,
}) });
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file; const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){ if (selectType === 'WARMUP') {
const liveCourseWarmMedia = { const liveCourseWarmMedia = {
contentType: 'WARMUP', contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE', mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId, mediaContent: resourceId,
mediaUrl: ossUrl, mediaUrl: ossUrl,
mediaName: folderName, mediaName: folderName,
size: folderSize size: folderSize,
} };
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia); this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{ } else {
// 最多添加九图片 // 最多添加九图片
const { liveCourseMediaRequests } = this.props.data; const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => { const list = _.filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE"; return item.mediaType == 'PICTURE';
}); });
if (list.length > 8) { if (list.length > 8) {
message.warning("最多添加9张图片"); message.warning('最多添加9张图片');
return; return;
} }
liveCourseMediaRequests.push({ liveCourseMediaRequests.push({
...@@ -78,61 +70,62 @@ class AddGraphicsIntro extends React.Component { ...@@ -78,61 +70,62 @@ class AddGraphicsIntro extends React.Component {
}); });
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests); this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
} }
};
}
changeDetail = (value) => { changeDetail = (value) => {
this.props.onChange('courseMedia', value); this.props.onChange('courseMedia', value);
} };
changeIntro = (value) => { changeIntro = (value) => {
this.props.onChange('introduce', value); this.props.onChange('introduce', value);
} };
whetherVisitorsJoinChange = ()=>{ whetherVisitorsJoinChange = () => {
if(this.props.data.whetherVisitorsJoin==="NO"){ if (this.props.data.whetherVisitorsJoin === 'NO') {
this.props.onChange('whetherVisitorsJoin','YES') this.props.onChange('whetherVisitorsJoin', 'YES');
}else{ } else {
this.props.onChange('whetherVisitorsJoin','NO') this.props.onChange('whetherVisitorsJoin', 'NO');
}
} }
};
shelfStateChange = ()=>{ shelfStateChange = () => {
if(this.props.data.shelfState==="NO"){ if (this.props.data.shelfState === 'NO') {
this.props.onChange('shelfState','YES') this.props.onChange('shelfState', 'YES');
}else{ } else {
this.props.onChange('shelfState','NO') this.props.onChange('shelfState', 'NO');
}
} }
};
render() { render() {
const {data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce } } = this.props; const {
data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce },
} = this.props;
const { showSelectFileModal, selectType } = this.state; const { showSelectFileModal, selectType } = this.state;
return ( return (
<div className="add-video__intro-info"> <div className='add-video__intro-info'>
<div className="allow-tourist-join"> <div className='allow-tourist-join'>
<span className="label">观看设置:</span> <span className='label'>观看设置:</span>
<div className="content"> <div className='content'>
<div> <div>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/> <Switch checked={whetherVisitorsJoin === 'YES' ? true : false} onChange={this.whetherVisitorsJoinChange} />
</div> </div>
<div> <div>
<div className="desc"> <div className='desc'>
<div>开启:允许未绑定手机号的学员观看</div> <div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看图文课</div> <div>关闭:仅限绑定了手机号的学员可以进入观看图文课</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="store-show"> <div className='store-show'>
<span className="label">学院展示:</span> <span className='label'>学院展示:</span>
<div className="content"> <div className='content'>
<Row> <Row>
<Col span={3}> <Col span={3}>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/> <Switch checked={shelfState === 'YES' ? true : false} onChange={this.shelfStateChange} />
</Col> </Col>
<Col span={21}> <Col span={21}>
<div className="desc"> <div className='desc'>
<div>开启:图文课将在学员学院图文课列表中展示</div> <div>开启:图文课将在学员学院图文课列表中展示</div>
<div>关闭:图文课将在学员学院图文课列表中隐藏</div> <div>关闭:图文课将在学员学院图文课列表中隐藏</div>
</div> </div>
...@@ -140,59 +133,65 @@ class AddGraphicsIntro extends React.Component { ...@@ -140,59 +133,65 @@ class AddGraphicsIntro extends React.Component {
</Row> </Row>
</div> </div>
</div> </div>
<div className="introduce required"> <div className='introduce required'>
<span className="label" style={{ marginTop: 5 }}>课程内容:</span> <span className='label' style={{ marginTop: 5 }}>
<div className="content"> 课程内容:
<div className="intro-list"> </span>
<div className="intro-list__item content-editor"> <div className='content'>
{(!id || loadcourseMedia) && <div className='intro-list'>
<div className='intro-list__item content-editor'>
{(!id || loadcourseMedia) && (
<GraphicsEditor <GraphicsEditor
id="content" id='content'
detail={{ detail={{
content: courseMedia content: courseMedia,
}}
onChange={(val) => {
this.changeDetail(val);
}} }}
onChange={(val) => { this.changeDetail(val) }}
/> />
} )}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="introduce"> <div className='introduce'>
<span className="label">课程简介:</span> <span className='label'>课程简介:</span>
<div className="content"> <div className='content'>
<div className="intro-list"> <div className='intro-list'>
<div className="intro-list__item introduce-editor"> <div className='intro-list__item introduce-editor'>
{(!id || loadintroduce) && {(!id || loadintroduce) && (
<GraphicsEditor <GraphicsEditor
id="intro" id='intro'
isIntro={true} isIntro={true}
detail={{ detail={{
content: introduce content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}} }}
onChange={(val) => { this.changeIntro(val) }}
/> />
} )}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* 选择暖场图文件弹窗 */} {/* 选择暖场图文件弹窗 */}
{ showSelectFileModal && {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
operateType="select" operateType='select'
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"} accept={selectType === 'INTRO' ? 'image/jpeg,image/png,image/jpg' : 'video/mp4,image/jpeg,image/png,image/jpg'}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] } selectTypeList={selectType === 'INTRO' ? ['JPG', 'JPEG', 'PNG'] : ['MP4', 'JPG', 'JPEG', 'PNG']}
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'} tooltip={selectType === 'INTRO' ? '支持文件类型:jpg、jpeg、png' : '支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal} isOpen={showSelectFileModal}
onClose={() => { onClose={() => {
this.setState({ showSelectFileModal: false }) this.setState({ showSelectFileModal: false });
}} }}
onSelect={this.handleSelectVideo} onSelect={this.handleSelectVideo}
/> />
} )}
</div> </div>
) );
} }
} }
......
.add-video__intro-info { .add-offline__intro-info {
.w-e-full-screen-editor { .w-e-full-screen-editor {
background: #fff !important; background: #fff !important;
} }
......
...@@ -3,20 +3,21 @@ ...@@ -3,20 +3,21 @@
* @Date: 2020-08-05 10:12:45 * @Date: 2020-08-05 10:12:45
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-11 16:44:42 * @LastEditTime: 2021-06-11 16:44:42
* @Description: 视频课-列表模块 * @Description: 线上课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import Service from '@/common/js/service'; import Service from '@/common/js/service';
import User from '@/common/js/user'; import User from '@/common/js/user';
import college from '@/common/lottie/college'; import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components'; import { PageControl, XMTable } from '@/components';
import { appId, LIVE_SHARE } from '@/domains/course-domain/constants'; import { LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService'; import CourseService from '@/domains/course-domain/CourseService';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal'; import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import OfflineCourseData from '@/modules/course-manage/offline-course/OfflineCourseData'; import OfflineCourseData from '@/modules/course-manage/offline-course/OfflineCourseData';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd'; import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
import moment from 'moment'; import moment from 'moment';
import React from 'react'; import React from 'react';
import { find, reduce, last } from 'underscore';
import { Route, withRouter } from 'react-router-dom'; import { Route, withRouter } from 'react-router-dom';
import ENUM from '../../../knowledge-base/ENUM.js'; import ENUM from '../../../knowledge-base/ENUM.js';
import PreviewOfflineModal from '../modal/PreviewOfflineModal'; import PreviewOfflineModal from '../modal/PreviewOfflineModal';
...@@ -29,7 +30,7 @@ class OfflineCourseList extends React.Component { ...@@ -29,7 +30,7 @@ class OfflineCourseList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
id: '', // 视频课ID id: '', // 线上课ID
studentIds: [], studentIds: [],
}; };
} }
...@@ -44,7 +45,7 @@ class OfflineCourseList extends React.Component { ...@@ -44,7 +45,7 @@ class OfflineCourseList extends React.Component {
handlePlanName = (planArray) => { handlePlanName = (planArray) => {
let planStr = ''; let planStr = '';
planArray.map((item, index) => { planArray.forEach((item, index) => {
if (index < planArray.length - 1) { if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、'; planStr = planStr + item.planName + '、';
} else { } else {
...@@ -64,13 +65,13 @@ class OfflineCourseList extends React.Component { ...@@ -64,13 +65,13 @@ class OfflineCourseList extends React.Component {
fixed: 'left', fixed: 'left',
render: (val, record) => { render: (val, record) => {
const { courseMediaVOS, courseName, offlinePlace, calendarTime, startTime, endTime } = record; const { courseMediaVOS, courseName, offlinePlace, calendarTime, startTime, endTime } = record;
const coverUrl = (_.find(courseMediaVOS, (data) => data.contentType === 'COVER') || {}).mediaUrl; const coverUrl = (find(courseMediaVOS, (data) => data.contentType === 'COVER') || {}).mediaUrl;
let isContinue = calendarTime.length > 1; let isContinue = calendarTime.length > 1;
_.reduce(calendarTime, (a, b) => { reduce(calendarTime, (a, b) => {
isContinue = isContinue && b - a === 86400000; isContinue = isContinue && b - a === 86400000;
return b; return b;
}); });
const lastTime = _.last(calendarTime); const lastTime = last(calendarTime);
const time = `${ const time = `${
!isContinue !isContinue
? calendarTime.map((item) => moment(item).format('MM-DD')).join('、') ? calendarTime.map((item) => moment(item).format('MM-DD')).join('、')
...@@ -78,7 +79,7 @@ class OfflineCourseList extends React.Component { ...@@ -78,7 +79,7 @@ class OfflineCourseList extends React.Component {
} ${moment(startTime).format('HH:mm')} ~ ${moment(endTime).format('HH:mm')}`; } ${moment(startTime).format('HH:mm')} ~ ${moment(endTime).format('HH:mm')}`;
return ( return (
<div className='record__item'> <div className='record__item'>
<img className='course-cover' src={coverUrl || defaultCoverUrl} /> <img className='course-cover' src={coverUrl || defaultCoverUrl} alt='' />
<div style={{ width: 175 }}> <div style={{ width: 175 }}>
<Tooltip title={courseName}> <Tooltip title={courseName}>
<div className='course-name'>{courseName}</div> <div className='course-name'>{courseName}</div>
...@@ -138,7 +139,9 @@ class OfflineCourseList extends React.Component { ...@@ -138,7 +139,9 @@ class OfflineCourseList extends React.Component {
width: 120, width: 120,
dataIndex: 'courseware', dataIndex: 'courseware',
render: (val, item, index) => { render: (val, item, index) => {
return <Switch disabled={item.courseState === 'EXPIRED'} checked={item.shelfState === 'YES'} onChange={() => this.changeShelfState(item)} />; return (
<Switch size='small' disabled={item.courseState === 'EXPIRED'} checked={item.shelfState === 'YES'} onChange={() => this.changeShelfState(item)} />
);
}, },
}, },
{ {
...@@ -152,14 +155,14 @@ class OfflineCourseList extends React.Component { ...@@ -152,14 +155,14 @@ class OfflineCourseList extends React.Component {
}, },
{ {
title: '报名时间', title: '报名时间',
width: 181, width: 200,
key: 'apply', key: 'apply',
dataIndex: 'apply', dataIndex: 'apply',
sorter: true, sorter: true,
render: (val, item) => { render: (val, item) => {
return ( return (
<div> <div style={{ whiteSpace: 'nowrap' }}>
{item.startTimeApply ? `${formatDate('MM-DD H:i', item.startTimeApply)} ~ ${formatDate('MM-DD H:i', item.endTimeApply)}` : '-'} {item.startTimeApply ? `${window.formatDate('MM-DD H:i', item.startTimeApply)} ~ ${window.formatDate('MM-DD H:i', item.endTimeApply)}` : '-'}
{item.whetherApplyFull === 'YES' && ( {item.whetherApplyFull === 'YES' && (
<span <span
style={{ style={{
...@@ -185,7 +188,7 @@ class OfflineCourseList extends React.Component { ...@@ -185,7 +188,7 @@ class OfflineCourseList extends React.Component {
dataIndex: 'created', dataIndex: 'created',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val); return <span style={{ whiteSpace: 'nowrap' }}>{window.formatDate('YYYY-MM-DD H:i', val)}</span>;
}, },
}, },
{ {
...@@ -360,8 +363,6 @@ class OfflineCourseList extends React.Component { ...@@ -360,8 +363,6 @@ class OfflineCourseList extends React.Component {
// 显示分享弹窗 // 显示分享弹窗
handleShowShareModal = (record, needStr = false) => { handleShowShareModal = (record, needStr = false) => {
const { courseId } = record; const { courseId } = record;
const _appId = appId;
const htmlUrl = `${LIVE_SHARE}offline_detail/${courseId}?id=${User.getStoreId()}`; const htmlUrl = `${LIVE_SHARE}offline_detail/${courseId}?id=${User.getStoreId()}`;
const longUrl = htmlUrl; const longUrl = htmlUrl;
const { courseName, courseMediaVOS } = record; const { courseName, courseMediaVOS } = record;
...@@ -437,7 +438,7 @@ class OfflineCourseList extends React.Component { ...@@ -437,7 +438,7 @@ class OfflineCourseList extends React.Component {
columns={this.parseColumns()} columns={this.parseColumns()}
onChange={this.handleChangeTable} onChange={this.handleChangeTable}
pagination={false} pagination={false}
scroll={{ x: 1500 }} scroll={{ x: 1300 }}
bordered bordered
className='offline-list-table' className='offline-list-table'
/> />
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* @Date: 2020-08-05 10:12:15 * @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 16:07:27 * @LastEditTime: 2020-12-26 16:07:27
* @Description: 视频课-操作模块 * @Description: 线上课-操作模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
......
...@@ -14,7 +14,7 @@ const hasExportPermission = (type) => { ...@@ -14,7 +14,7 @@ const hasExportPermission = (type) => {
return Permission.hasInteractiveExport(); return Permission.hasInteractiveExport();
} }
// 视频课导出权限 // 线上课导出权限
if (type === 'videoClass') { if (type === 'videoClass') {
return Permission.hasVideoClassExport(); return Permission.hasVideoClassExport();
} }
......
...@@ -49,14 +49,16 @@ ...@@ -49,14 +49,16 @@
} }
} }
.course-catalog{ .course-catalog{
margin-bottom:16px; margin-bottom:24px;
margin-top:16px; margin-top:24px;
} }
.course-ware { .course-ware {
display: flex; display: flex;
align-items: center; align-items: center;
margin-bottom: 4px; margin-bottom: 4px;
&__index {
width: 18px;
}
&__img { &__img {
width: 24px; width: 24px;
margin-right: 4px; margin-right: 4px;
...@@ -75,7 +77,19 @@ ...@@ -75,7 +77,19 @@
.img-content { .img-content {
width: 298px; width: 298px;
height: 172px; height: 172px;
position: relative;
.tag {
border-radius: 2px;
background: rgba(51, 51, 51, .2);
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #FFF;
position: absolute;
top: 8px;
left: 8px;
}
img { img {
width: 100%; width: 100%;
height: 100%; height: 100%;
...@@ -85,7 +99,7 @@ ...@@ -85,7 +99,7 @@
.empty-img { .empty-img {
width: 298px; width: 298px;
height: 172px; height: 172px;
border: 1px dashed #EBEBEB; border: 1px dashed #ebebeb;
border-radius: 4px; border-radius: 4px;
padding: 12px; padding: 12px;
color: #999; color: #999;
...@@ -94,12 +108,17 @@ ...@@ -94,12 +108,17 @@
} }
.opt-btns { .opt-btns {
margin-top: 8px; margin-bottom: 8px;
display: flex; .span {
align-items: center; color: #ccc;
margin-left: 8px;
}
.defalut-span {
cursor: pointer;
color: #2966ff;
}
.tips { .tips {
margin-left: 12px; margin-top: 8px;
color: #999; color: #999;
} }
} }
...@@ -115,18 +134,97 @@ ...@@ -115,18 +134,97 @@
color: #333; color: #333;
} }
} }
.upload-video {
display: flex;
margin-bottom: 24px;
.sub-content { .sub-content {
margin-left: 85px;
margin-top: 4px; margin-top: 4px;
.btn-wrap {
display: flex;
.course-ware--empty {
margin-left: 12px;
line-height: 28px;
}
}
.tips { .tips {
margin-left: 4px; margin-top: 8px;
color: #999; color: #999;
} }
} }
} }
.course-chapter-list-wrap {
position: relative;
margin-left: 85px;
border: 1px solid #E8E8E8;
width: 630px;
.course-chapter-total {
height: 40px;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
z-index: 10;
background: #fff;
width: 628px;
text-indent: 16px;
line-height: 40px;
}
.course-chapter-list {
max-height: 245px;
min-height: 130px;
overflow-y: auto ;
border-radius: 4px;
padding: 16px;
.course-ware {
display: flex;
align-items: center;
margin-bottom: 22px;
color: #666;
&:last-child {
margin-bottom: 0px;
}
&__img {
width: 24px;
margin-right: 8px;
margin-left: 16px;
}
&__name {
color: #333;
width: 353px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
margin-right: 24px;
}
.course-chapter__opt {
display: flex;
color: #2966ff;
width: 168px;
.line {
color: #bfbfbf;
margin-left: 4px;
margin-right: 4px;
}
.delete,
.rename,
.up,
.down {
cursor: pointer;
}
.up,
.down {
&.disabled {
color: rgba(204, 204, 204, 1);
}
}
}
}
}
}
}
.footer { .footer {
position: fixed; position: fixed;
left: 196px; left: 196px;
...@@ -138,10 +236,25 @@ ...@@ -138,10 +236,25 @@
justify-content: flex-end; justify-content: flex-end;
padding-right: 72px; padding-right: 72px;
background: #fff; background: #fff;
border-top: 1px solid #E8E8E8; border-top: 1px solid #ccc2c2;
z-index: 999; z-index: 999;
.ant-btn { .ant-btn {
margin-left: 10px; margin-left: 10px;
} }
} }
} }
.chapter-popover {
.ant-popover-message-title {
padding-left: 0;
}
.ant-form-item {
margin-bottom: 0!important;
}
.ant-form-item-explain.ant-form-item-explain-error {
height: 24px;
}
.ant-form-item-explain {
min-height: 0;
}
}
\ No newline at end of file
.video-course-detail {
padding-bottom: 40px;
.box {
.course-detail {
display: flex;
border-bottom: 2px solid #E8E8E8;
padding-bottom: 24px;
&__img {
margin-right: 24px;
width: 300px;
height: 170px;
background: #FFFFFF;
border-radius: 4px;
img {
width: 300px;
height: 170px;
border-radius: 4px;
}
}
&__info {
display: flex;
flex-direction: column;
.info__title {
font-size: 20px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 28px;
margin-bottom: 16px;
}
.info__category, .info__chapterNum {
width: 100%;
height: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
margin-bottom: 10px;
}
}
}
.course-chapter {
padding-top: 24px;
&__total {
width: 100%;
height: 20px;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 20px;
margin-bottom: 24px;
}
&__list {
.course-ware {
display: flex;
height: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 28px;
cursor: pointer;
&:hover {
color: #2966FF;
}
&__index {
width: 20px;
}
&__img {
width: 20px;
height: 20px;
margin-left: 16px;
margin-right: 8px;
}
&__name {
width: 700px;
}
}
}
}
}
}
\ No newline at end of file
/*
* @Author: wufan
* @Date: 2020-04-28 18:05:30
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-13 15:26:11
* @Description: 线上课课程课节详情
*/
import React,{useEffect, useState} from 'react';
import Breadcrumbs from "@/components/Breadcrumbs";
import { withRouter } from "react-router-dom";
import CourseService from '@/domains/course-domain/CourseService'
import underscore from 'underscore';
import ScanFileModal from '@/modules/resource-disk/modal/ScanFileModal.jsx';
import { FileTypeIcon } from '@/common/constants/academic/lessonEnum'
import BaseService from "@/domains/basic-domain/baseService";
import {YZ_APPId,YZ_PREVIEW_URL} from '@/domains/basic-domain/constants';
import PreviewFileModal from '@/bu-components/PreviewFileModal';
import './VideoCourseDetail.less';
declare var getParameterByName: any;
declare var window: any;
const FileTypeIconMap:any = FileTypeIcon
function VideoCourseDetail(){
const courseId = window.getParameterByName("courseId"); // 课程ID
const [coverUrl,setCoverUrl] = useState("");
const [videoName,setVideoName] = useState("");
const [scheduleVideoUrl,setScheduleVideoUrl] = useState("");
const [courseChapterList,setCourseChapterList] = useState<Array<Object>>([]);
const [courseName,setCourseName] = useState("");
const [categoryName,setCategoryName] = useState("");
const [scanFileModal,setScanFileModal] = useState<any>(null);
const [showPreviewModal,setShowPreviewModal] = useState(false); //是否显示loading
// const [previewing,setPreviewing] = useState(false); //是否正在预览
const [previewStatus,setPreviewStatus] = useState('UPLOAD'); //预览文件的生成状态
const [url,setUrl] = useState('');
let previewing = false;
useEffect(()=>{
handleFetchScheudleDetail(courseId);
},[courseId])
// 获取线上课详情
function handleFetchScheudleDetail(courseId: string){
CourseService.videoScheduleDetail({
courseId
}).then((res) => {
const { result = {} } = res || {}
const { courseName, courseMediaVOS, categoryName, courseChapterVOList =[] } = result
let coverId:string = "";
let coverUrl: string = "";
let videoType: string = "";
let videoDuration: number = 0;
let videoName: string = "";
let scheduleVideoUrl: string = "";
courseMediaVOS.map((item:any) => {
switch (item.contentType) {
case 'COVER':
coverId = item.mediaContent
coverUrl = item.mediaUrl
break
case 'SCHEDULE':
videoDuration = item.videoDuration
videoName = item.mediaName
scheduleVideoUrl = item.mediaUrl
videoType = item.mediaType
break
default:
break
}
return item
})
setCoverUrl(coverUrl);
setVideoName(videoName);
setScheduleVideoUrl(scheduleVideoUrl);
setCourseName(courseName);
setCategoryName(categoryName);
setCourseChapterList(courseChapterVOList);
})
}
async function handleScanFileModal(fileType: string = "MP4", fileObj:any){
const {fileVersionId,name,mediaUrl,id} = fileObj;
if(fileType === "VIDEO"){
const scanFileModal = (
<ScanFileModal
fileType={fileType}
item={fileObj}
close={() => {
setScanFileModal(null);
}}
/>
);
setScanFileModal(scanFileModal)
}else{
if(!fileVersionId){
setShowPreviewModal(true);
previewing = true;
setPreviewStatus('UPLOAD');
const uploadParams ={
fileUrl:mediaUrl,
yoZoTypeEnum:'UPLOAD'
}
const uploadSign:any = await BaseService.getYoZoSign(uploadParams);
BaseService.yoZoUpload(mediaUrl,YZ_APPId,uploadSign).then(async function (response){
const saveParams ={
fileVersionId:response.data.data.fileVersionId,
courseChapterId:id
}
BaseService.saveFileVersionIdByCourseChapter(saveParams);
if(previewing){
const previewParams ={
fileVersionId:response.data.data.fileVersionId,
yoZoTypeEnum:'VIEW',
htmlTitle:name
}
const previewSign = await BaseService.getYoZoSign(previewParams);
const url = `${YZ_PREVIEW_URL}?fileVersionId=${response.data.data.fileVersionId}&appId=${YZ_APPId}&sign=${previewSign}&htmlTitle=${name}`
setPreviewStatus('UPLOAD_SUCCESS');
setUrl(url)
}
})
}else{
const previewParams ={
fileVersionId,
yoZoTypeEnum:'VIEW',
htmlTitle:name
}
const previewSign = await BaseService.getYoZoSign(previewParams);
const url = `${YZ_PREVIEW_URL}?fileVersionId=${fileVersionId}&appId=${YZ_APPId}&sign=${previewSign}&htmlTitle=${name}`
const a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('href', url);
a.setAttribute('target', '_blank');
a.click();
document.body.removeChild(a)
}
}
}
// function previewingSet(){
// return new Promise(async (resolve) => {
// setShowPreviewModal(true);
// setPreviewing(true);
// setPreviewStatus('UPLOAD');
// resolve(true);
// })
// }
function cancelPreview(){
setShowPreviewModal(false);
// setPreviewing(false);
previewing = false;
setPreviewStatus('UPLOAD');
}
return <div className="page video-course-detail">
<Breadcrumbs
navList="课程详情"
goBack={() => {
window.RCHistory.goBack();
}}
/>
<div className="box">
<div className="course-detail">
<div className='course-detail__img'>
{/* 如果视频和封面都没有上传的话, 那么就显示缺省, 如果上传了视频, 那么封面图就默认显示视频的第一帧, 如果上传了封面图, 那么就显示上传的封面图 */}
<img src={coverUrl || `https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png`} alt='' />
</div>
<div className="course-detail__info">
<div className="info__title">{courseName}</div>
<div className="info__category">{`分类:${categoryName}`}</div>
<div className="info__chapterNum">{`课节数量:${courseChapterList.length}`}</div>
</div>
</div>
<div className="course-chapter">
<div className="course-chapter__total">{`共${courseChapterList.length}个课节`}</div>
<div className="course-chapter__list">
<If condition={courseChapterList.length > 0}>
{
underscore.map(courseChapterList,(item: any,index: number) => {
return <div className='course-ware' onClick={()=>{handleScanFileModal(item.mediaType,item)}} key={index}>
<div className="course-ware__index">{index < 9 ? `0${index + 1 } ` : index + 1}</div>
<img className='course-ware__img' src={FileTypeIconMap[item.mediaType]} alt='' />
<div className='course-ware__name'>{item.name}</div>
</div>
})
}
</If>
</div>
</div>
</div>
{ showPreviewModal &&
<PreviewFileModal onCancel={()=>cancelPreview()} previewStatus={previewStatus} url={url}/>
}
{scanFileModal}
</div>
}
export default withRouter(VideoCourseDetail);
\ No newline at end of file
...@@ -6,30 +6,23 @@ ...@@ -6,30 +6,23 @@
* @Description: 添加直播-简介 * @Description: 添加直播-简介
*/ */
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { Col, message, Row, Switch } from 'antd';
import React from 'react'; import React from 'react';
import { Input, message, Upload, Radio, Row, Col, Button, Popover, Switch } from 'antd';
import Service from '@/common/js/service';
import GraphicsEditor from '../../components/GraphicsEditor'; import GraphicsEditor from '../../components/GraphicsEditor';
import User from '@/common/js/user'; import { filter } from 'underscore';
import UploadOss from '@/core/upload';
import './AddVideoIntro.less'; import './AddVideoIntro.less';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components';
const { TextArea } = Input;
const defaultCover = 'https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1599635741526.png'; const defaultCover = 'https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1599635741526.png';
class AddVideoIntro extends React.Component { class AddVideoIntro extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
warmUrl: defaultCover, warmUrl: defaultCover,
showSelectFileModal: false, showSelectFileModal: false,
diskList: [], diskList: [],
selectType:null selectType: null,
} };
} }
// 上传封面图 // 上传封面图
...@@ -40,34 +33,34 @@ class AddVideoIntro extends React.Component { ...@@ -40,34 +33,34 @@ class AddVideoIntro extends React.Component {
imageFile, imageFile,
showCutModal: true, showCutModal: true,
}); });
} };
// 选择暖场资源 // 选择暖场资源
handleSelectVideo = (file) => { handleSelectVideo = (file) => {
const { selectType } = this.state; const { selectType } = this.state;
this.setState({ this.setState({
showSelectFileModal: false showSelectFileModal: false,
}) });
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file; const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){ if (selectType === 'WARMUP') {
const liveCourseWarmMedia = { const liveCourseWarmMedia = {
contentType: 'WARMUP', contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE', mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId, mediaContent: resourceId,
mediaUrl: ossUrl, mediaUrl: ossUrl,
mediaName: folderName, mediaName: folderName,
size: folderSize size: folderSize,
} };
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia); this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{ } else {
// 最多添加九图片 // 最多添加九图片
const { liveCourseMediaRequests } = this.props.data; const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => { const list = filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE"; return item.mediaType === 'PICTURE';
}); });
if (list.length > 8) { if (list.length > 8) {
message.warning("最多添加9张图片"); message.warning('最多添加9张图片');
return; return;
} }
liveCourseMediaRequests.push({ liveCourseMediaRequests.push({
...@@ -80,104 +73,120 @@ class AddVideoIntro extends React.Component { ...@@ -80,104 +73,120 @@ class AddVideoIntro extends React.Component {
}); });
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests); this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
} }
};
}
changeIntro = (value) => { changeIntro = (value) => {
this.props.onChange('introduce', value); this.props.onChange('introduce', value);
} };
handleUpload = (Blob) => { handleUpload = (Blob) => {
this.setState({ this.setState({
showSelectFileModal: true, showSelectFileModal: true,
selectType:'INTRO' selectType: 'INTRO',
}) });
} };
whetherVisitorsJoinChange = ()=>{ whetherVisitorsJoinChange = () => {
if(this.props.data.whetherVisitorsJoin==="NO"){ if (this.props.data.whetherVisitorsJoin === 'NO') {
this.props.onChange('whetherVisitorsJoin','YES') this.props.onChange('whetherVisitorsJoin', 'YES');
}else{ } else {
this.props.onChange('whetherVisitorsJoin','NO') this.props.onChange('whetherVisitorsJoin', 'NO');
} }
} };
shelfStateChange = ()=>{ shelfStateChange = () => {
if(this.props.data.shelfState==="NO"){ if (this.props.data.shelfState === 'NO') {
this.props.onChange('shelfState','YES') this.props.onChange('shelfState', 'YES');
}else{ } else {
this.props.onChange('shelfState','NO') this.props.onChange('shelfState', 'NO');
} }
} };
render() { render() {
const {data: { whetherVisitorsJoin,liveCourseMediaRequests = [], shelfState, id, introduce, loadintroduce } } = this.props; const {
const {showSelectFileModal,selectType} = this.state data: { whetherVisitorsJoin, shelfState, id, introduce, loadintroduce },
} = this.props;
const { showSelectFileModal, selectType } = this.state;
return ( return (
<div className="add-video__intro-info"> <div className='add-video__intro-info'>
<div className="allow-tourist-join"> <div className='allow-tourist-join'>
<span className="label">观看设置:</span> <span className='label'>观看设置:</span>
<div className="content"> <div className='content'>
<div> <div>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/> <Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} />
</div> </div>
<div> <div>
<div className="desc"> <div className='desc'>
<div>开启:允许未绑定手机号的学员观看</div> <Choose>
<div>关闭:仅限绑定了手机号的学员可以进入观看视频</div> <When condition={whetherVisitorsJoin === 'NO'}>
<div>已开启,学员需绑定手机号才可观看</div>
</When>
<Otherwise>
<div>已关闭,学员无需绑定手机号即可观看</div>
</Otherwise>
</Choose>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div className="store-show"> <div className='store-show'>
<span className="label">学院展示:</span> <span className='label'>学院展示:</span>
<div className="content"> <div className='content'>
<Row> <Row>
<Col span={3}> <Col span={3}>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/> <Switch checked={shelfState === 'YES' ? true : false} onChange={this.shelfStateChange} />
</Col> </Col>
<Col span={21}> <Col span={21}>
<div className="desc"> <div className='desc'>
<div>开启:此视频将在学员学院的视频列表中出现</div> <Choose>
<div>关闭:此视频将在学员学院的视频列表中隐藏</div> <When condition={shelfState === 'YES'}>
<div>已开启,课程将在该学院的学员课程列表中显示</div>
</When>
<Otherwise>
<div>已关闭,课程将在该学院的学员课程列表中隐藏</div>
</Otherwise>
</Choose>
</div> </div>
</Col> </Col>
</Row> </Row>
</div> </div>
</div> </div>
<div className="introduce"> <div className='introduce'>
<span className="label">视频课简介:</span> <span className='label'>课程简介:</span>
<div className="content"> <div className='content'>
<div className="intro-list"> <div className='intro-list'>
<div className="intro-list__item introduce-editor"> <div className='intro-list__item introduce-editor'>
{(!id || loadintroduce) && {(!id || loadintroduce) && (
<GraphicsEditor <GraphicsEditor
id="intro" maxLimit={1000}
id='intro'
isIntro={true} isIntro={true}
detail={{ detail={{
content: introduce content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}} }}
onChange={(val) => { this.changeIntro(val) }}
/> />
} )}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* 选择暖场图文件弹窗 */} {/* 选择暖场图文件弹窗 */}
{ showSelectFileModal && {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
operateType="select" operateType='select'
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"} accept={selectType === 'INTRO' ? 'image/jpeg,image/png,image/jpg' : 'video/mp4,image/jpeg,image/png,image/jpg'}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] } selectTypeList={selectType === 'INTRO' ? ['JPG', 'JPEG', 'PNG'] : ['MP4', 'JPG', 'JPEG', 'PNG']}
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'} tooltip={selectType === 'INTRO' ? '支持文件类型:jpg、jpeg、png' : '支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal} isOpen={showSelectFileModal}
onClose={() => { onClose={() => {
this.setState({ showSelectFileModal: false }) this.setState({ showSelectFileModal: false });
}} }}
onSelect={this.handleSelectVideo} onSelect={this.handleSelectVideo}
/> />
} )}
</div> </div>
) );
} }
} }
......
...@@ -32,14 +32,17 @@ ...@@ -32,14 +32,17 @@
} }
.store-show{ .store-show{
display:flex; display:flex;
margin-top:16px; margin-top:24px;
margin-bottom:16px; margin-bottom:24px;
.desc{ .desc{
margin-left:16px; margin-left:11px;
font-size:14px; font-size:14px;
color:#999; color:#999;
display:inline-block; display:inline-block;
} }
.content {
width: 400px;
}
} }
.radio { .radio {
display: block; display: block;
......
import React from 'react';
import './ChapterList.less';
function ChapterList(props){
const { courseChapterList } = props;
return <div className='chapter-list-component'>
<If condition={courseChapterList.length > 0}>
{
_.map(courseChapterList,(item,index) => {
return <div className='course-ware'>
<div className='course-ware__index'>{index < 9 ? `0${index + 1 } ` : `${index + 1 } `}</div>
<div className="course-ware__detail">
<div className='course-ware__detail__name'>{item.mediaName}</div>
{ item.mediaType === 'VIDEO' &&
<div className='course-ware__detail__duration'>{window.formatDuration(item.videoDuration)}</div>
}
</div>
</div>
})
}
</If>
</div>
}
export default ChapterList;
\ No newline at end of file
.chapter-list-component {
.course-ware {
display: flex;
padding: 10px 0;
border-bottom: 1px dashed #EEEEEE;
&:last-child {
border-bottom: none;
}
&__index {
width: 18px;
height: 18px;
font-size: 13px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #999999;
line-height: 18px;
}
&__detail {
display: flex;
flex-direction: column;
width: calc(~'100% - 18px');
&__name {
width: 267px;
font-size: 13px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 21px;
margin-bottom: 4px;
}
&__duration {
color: #999999;
}
}
}
}
\ No newline at end of file
import User from "@/common/js/user";
import CourseService from "@/domains/course-domain/CourseService";
import React from "react";
import { Modal } from "antd";
import { FileTypeIcon } from '@/common/constants/academic/lessonEnum'
import "./LearningDetailModal.less";
class LearningDetailModal extends React.Component {
constructor(props) {
super(props);
this.state = {
courseChapterList: [],
};
}
componentDidMount() {
this.handleFetchDataList();
}
// 获取观看视频数据列表
handleFetchDataList = () => {
const { courseId, data } = this.props;
const params = {
courseId,
storeId: User.getStoreId(),
storeCustomerId: data.storeCustomerId,
};
CourseService.lineDetailWatchInfo(params).then((res) => {
const { result = [] } = res;
this.setState({
courseChapterList: result
});
});
};
render() {
const { title, onClose, onOk } = this.props;
const { courseChapterList } = this.state;
return (
<Modal
footer={null}
visible={true}
title={title}
width={680}
maskClosable={false}
closeIcon={
<span className="icon iconfont modal-close-icon">&#xe6ef;</span>
}
onCancel={onClose}
onOk={onOk}
className="learning-detail-modal"
>
<div className="course-chapter__list">
<If condition={courseChapterList.length > 0}>
{_.map(courseChapterList, (item, index) => {
return (
<div className="course-wrap">
<div className="course-ware" key={index}>
<div className="course-ware__index">{`${
index < 9 ? `0${index + 1}` : index + 1
} `}</div>
<img className='course-ware__img' src={FileTypeIcon[item.mediaType]} alt='' />
<div className="course-ware__name">{item.courseChapterName && item.courseChapterName.replace('.MP4','')}</div>
</div>
<div className={`progress ${item.progress === 100 ? 'finish' :''}`}>{`${item.progress === 100 ? '已完成' : `${item.progress}%`}`}</div>
</div>
);
})}
</If>
</div>
</Modal>
);
}
}
export default LearningDetailModal;
.learning-detail-modal {
.course-chapter {
padding-top: 24px;
&__list {
.course-wrap {
display: flex;
justify-content: space-between;
.course-ware {
display: flex;
height: 20px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 28px;
&__index {
width: 20px;
}
&__img {
width: 20px;
height: 20px;
margin-left: 12px;
margin-right: 8px;
}
&__name {
width: 500px;
}
}
.progress {
&.finish {
color: RGBA(101, 202, 168, 1);
}
}
}
}
}
}
/* /*
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:11:57 * @Date: 2020-08-05 10:11:57
* @LastEditors: fusanqiasng * @LastEditors: yuananting
* @LastEditTime: 2021-05-28 20:14:37 * @LastEditTime: 2021-07-12 14:14:47
* @Description: 视频课-搜索模块 * @Description: 线上课-搜索模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -56,22 +56,17 @@ class VideoCourseFilter extends React.Component { ...@@ -56,22 +56,17 @@ class VideoCourseFilter extends React.Component {
this.getTeacherList() this.getTeacherList()
this.queryCategoryTree() this.queryCategoryTree()
} }
// 查询分类树 // 查询分类树
queryCategoryTree = (categoryName = '') => { queryCategoryTree = ()=> {
let query = { const params= {
bizType: 'QUESTION', storeId:User.getStoreId()
source: 2,
categoryName,
tenantId: User.getStoreId(),
userId: User.getStoreUserId(),
count: false,
} }
AidToolService.queryExternalCategoryTree(query).then((res) => { StoreService.getStoreDetail(params).then((res) => {
const { categoryList = [] } = res.result const { result = {} } = res;
console.log(this.renderTreeNodes(categoryList)) result.coursePackageId && AidToolService.queryCategoryTreeByPackage({coursePackageId: result.coursePackageId}).then((res) => {
this.setState({ const { result = [] } = res;
categoryList: this.renderTreeNodes(categoryList), this.setState({categoryList: this.renderTreeNodes(result)})
categoryName,
}) })
}) })
} }
...@@ -192,10 +187,10 @@ class VideoCourseFilter extends React.Component { ...@@ -192,10 +187,10 @@ class VideoCourseFilter extends React.Component {
<Row type='flex' justify='space-between' align='top'> <Row type='flex' justify='space-between' align='top'>
<div className='search-condition'> <div className='search-condition'>
<div className='search-condition__item'> <div className='search-condition__item'>
<span className='search-name'>视频课名称:</span> <span className='search-name'>线上课名称:</span>
<Search <Search
value={courseName} value={courseName}
placeholder='搜索视频课名称' placeholder='搜索线上课名称'
onChange={(e) => { onChange={(e) => {
this.handleChangeQuery('courseName', e.target.value) this.handleChangeQuery('courseName', e.target.value)
}} }}
......
import { Dropdown, message, Modal, Switch, Table, Tooltip } from 'antd'; import React from 'react';
import User from '@/common/js/user'; import { Modal, message, Tooltip, Switch, Dropdown } from 'antd';
import _ from 'underscore';
import { PageControl } from '@/components'; import { PageControl } from '@/components';
import { LIVE_SHARE } from '@/domains/course-domain/constants'; import { LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService'; import { Route, withRouter } from 'react-router-dom';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal'; import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import React from 'react'; import CourseService from '@/domains/course-domain/CourseService';
import RelatedPlanModal from '../../modal/RelatedPlanModal'; import RelatedPlanModal from '../../modal/RelatedPlanModal';
import WatchDataModal from '../modal/WatchDataModal'; import User from '@/common/js/user';
import VideoCourseDetail from '../VideoCourseDetail';
import WatchData from './WatchData';
import { XMTable } from '@/components'; import { XMTable } from '@/components';
import college from '@/common/lottie/college'; import college from '@/common/lottie/college';
import './VideoCourseList.less'; import './VideoCourseList.less';
...@@ -32,20 +35,19 @@ class VideoCourseList extends React.Component { ...@@ -32,20 +35,19 @@ class VideoCourseList extends React.Component {
} }
} }
// 跳转课程详情页
handleLinkToCourseDetail = (courseId) => {
const { match } = this.props;
window.RCHistory.push(`${match.url}/video-course-detail?courseId=${courseId}`);
};
// 观看数据弹窗 // 观看数据弹窗
handleShowWatchDataModal = (record) => { handleShowWatchDataModal = (item) => {
const watchDataModal = ( const { match } = this.props;
<WatchDataModal window.RCHistory.push({
type='videoCourseList' pathname: `${match.url}/course-data?courseName=${item.courseName}&courseId=${item.id}`,
data={record}
close={() => {
this.setState({
watchDataModal: null,
}); });
}}
/>
);
this.setState({ watchDataModal });
}; };
// 请求表头 // 请求表头
...@@ -54,23 +56,21 @@ class VideoCourseList extends React.Component { ...@@ -54,23 +56,21 @@ class VideoCourseList extends React.Component {
const { ShelfLoading } = this.state; const { ShelfLoading } = this.state;
const columns = [ const columns = [
{ {
title: '视频课', title: '线上课',
key: 'scheduleName', key: 'scheduleName',
dataIndex: 'scheduleName', dataIndex: 'scheduleName',
width: 321, width: 321,
fixed: 'left', fixed: 'left',
render: (val, record) => { render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record; const { coverUrl } = record;
return ( return (
<div className='record__item'> <div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img <img
className='course-cover' className='course-cover'
src={ src={
coverUrl || coverUrl || 'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png'
(type === 'internal' ? `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast` : 'https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png')
} }
alt='' alt='封面图'
/> />
<Choose> <Choose>
<When condition={record.courseName.length > 25}> <When condition={record.courseName.length > 25}>
...@@ -101,7 +101,7 @@ class VideoCourseList extends React.Component { ...@@ -101,7 +101,7 @@ class VideoCourseList extends React.Component {
), ),
key: 'categoryName', key: 'categoryName',
dataIndex: 'categoryName', dataIndex: 'categoryName',
width: 200, width: 150,
render: (val, record) => { render: (val, record) => {
return ( return (
<Choose> <Choose>
...@@ -119,20 +119,14 @@ class VideoCourseList extends React.Component { ...@@ -119,20 +119,14 @@ class VideoCourseList extends React.Component {
}, },
}, },
{ {
title: '创建人', title: '课节数',
key: 'createName', key: 'chapterNum',
dataIndex: 'createName', dataIndex: 'chapterNum',
className: 'chapterNum',
width: 100, width: 100,
render: (val) => { align: 'right',
return ( render: (val, item) => {
<div> return <div onClick={() => this.handleLinkToCourseDetail(item.id)}>{val || 1}</div>;
{val && (
<Tooltip title={val}>
<div>{val.length > 4 ? `${val.slice(0, 4)}...` : val}</div>
</Tooltip>
)}
</div>
);
}, },
}, },
{ {
...@@ -159,6 +153,7 @@ class VideoCourseList extends React.Component { ...@@ -159,6 +153,7 @@ class VideoCourseList extends React.Component {
render: (val, item, index) => { render: (val, item, index) => {
return ( return (
<Switch <Switch
size='small'
loading={ShelfLoading} loading={ShelfLoading}
checked={item.shelfState === 'YES'} checked={item.shelfState === 'YES'}
defaultChecked={item.shelfState} defaultChecked={item.shelfState}
...@@ -171,11 +166,33 @@ class VideoCourseList extends React.Component { ...@@ -171,11 +166,33 @@ class VideoCourseList extends React.Component {
}, },
{ {
title: '观看学员数', title: '观看学员数',
width: 110, width: 150,
key: 'watchUserCount', key: 'watchUserCount',
dataIndex: 'watchUserCount', dataIndex: 'watchUserCount',
align: 'right',
render: (val, item) => { render: (val, item) => {
return <div className='watchUserCount'>{val || 0}</div>; return (
<div className='watchUserCount' onClick={() => this.handleShowWatchDataModal(item)}>
{val || 0}
</div>
);
},
},
{
title: '创建人',
key: 'createName',
dataIndex: 'createName',
width: 100,
render: (val) => {
return (
<div>
{val && (
<Tooltip title={val}>
<div>{val.length > 4 ? `${val.slice(0, 4)}...` : val}</div>
</Tooltip>
)}
</div>
);
}, },
}, },
{ {
...@@ -185,7 +202,7 @@ class VideoCourseList extends React.Component { ...@@ -185,7 +202,7 @@ class VideoCourseList extends React.Component {
dataIndex: 'created', dataIndex: 'created',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val); return window.formatDate('YYYY-MM-DD H:i', val);
}, },
}, },
{ {
...@@ -195,7 +212,7 @@ class VideoCourseList extends React.Component { ...@@ -195,7 +212,7 @@ class VideoCourseList extends React.Component {
dataIndex: 'updated', dataIndex: 'updated',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val); return window.formatDate('YYYY-MM-DD H:i', val);
}, },
}, },
{ {
...@@ -211,7 +228,7 @@ class VideoCourseList extends React.Component { ...@@ -211,7 +228,7 @@ class VideoCourseList extends React.Component {
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter> <Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => { {record.relatedPlanList.map((item, index) => {
return ( return (
<span> <span key={item.planId}>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>} {item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}
</span> </span>
); );
...@@ -230,22 +247,17 @@ class VideoCourseList extends React.Component { ...@@ -230,22 +247,17 @@ class VideoCourseList extends React.Component {
title: '操作', title: '操作',
key: 'operate', key: 'operate',
dataIndex: 'operate', dataIndex: 'operate',
width: 210, width: 160,
fixed: 'right', fixed: 'right',
render: (val, record) => { render: (val, record) => {
return ( return (
<div className='operate'> <div className='operate'>
<div className='operate__item' onClick={() => this.handleShowWatchDataModal(record)}>
观看数据
</div>
<If condition={type === 'internal'}> <If condition={type === 'internal'}>
<span className='operate__item split'> | </span>
<div className='operate__item' onClick={() => this.handleShowShareModal(record)}> <div className='operate__item' onClick={() => this.handleShowShareModal(record)}>
分享 分享
</div> </div>
</If>
<span className='operate__item split'> | </span> <span className='operate__item split'> | </span>
</If>
<Dropdown overlay={this.renderMoreOperate(record)}> <Dropdown overlay={this.renderMoreOperate(record)}>
<span className='more-operate'> <span className='more-operate'>
<span className='operate-text'>更多</span> <span className='operate-text'>更多</span>
...@@ -260,7 +272,7 @@ class VideoCourseList extends React.Component { ...@@ -260,7 +272,7 @@ class VideoCourseList extends React.Component {
}, },
]; ];
type !== 'internal' && columns.splice(2, 1); type !== 'internal' && columns.splice(5, 1);
return columns; return columns;
}; };
...@@ -296,7 +308,7 @@ class VideoCourseList extends React.Component { ...@@ -296,7 +308,7 @@ class VideoCourseList extends React.Component {
handlePlanName = (planArray) => { handlePlanName = (planArray) => {
let planStr = ''; let planStr = '';
planArray.map((item, index) => { planArray.forEach((item, index) => {
if (index < planArray.length - 1) { if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、'; planStr = planStr + item.planName + '、';
} else { } else {
...@@ -327,7 +339,7 @@ class VideoCourseList extends React.Component { ...@@ -327,7 +339,7 @@ class VideoCourseList extends React.Component {
}); });
}; };
// 删除视频 // 删除线上
handleDeleteVideoCourse = (scheduleId) => { handleDeleteVideoCourse = (scheduleId) => {
Modal.confirm({ Modal.confirm({
title: '你确定要删除此视频课吗?', title: '你确定要删除此视频课吗?',
...@@ -369,7 +381,7 @@ class VideoCourseList extends React.Component { ...@@ -369,7 +381,7 @@ class VideoCourseList extends React.Component {
data={shareData} data={shareData}
type='videoClass' type='videoClass'
courseDivision={type} courseDivision={type}
title='视频课' title='线上课'
close={() => { close={() => {
this.setState({ this.setState({
shareLiveModal: null, shareLiveModal: null,
...@@ -446,7 +458,7 @@ class VideoCourseList extends React.Component { ...@@ -446,7 +458,7 @@ class VideoCourseList extends React.Component {
); );
}; };
render() { render() {
const { dataSource = [], totalCount, query, type } = this.props; const { dataSource = [], totalCount, query, type, match } = this.props;
const { current, size } = query; const { current, size } = query;
const { RelatedPlanModalVisible, selectPlanList, selectCourseId } = this.state; const { RelatedPlanModalVisible, selectPlanList, selectCourseId } = this.state;
return ( return (
...@@ -465,16 +477,6 @@ class VideoCourseList extends React.Component { ...@@ -465,16 +477,6 @@ class VideoCourseList extends React.Component {
scroll={{ x: 1500 }} scroll={{ x: 1500 }}
className='video-list-table' className='video-list-table'
/> />
{/* <Table
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
onChange={this.handleChangeTable}
pagination={false}
scroll={{ x: 1500 }}
bordered
className='video-list-table'
/> */}
<div className='box-footer'> <div className='box-footer'>
<PageControl <PageControl
...@@ -499,9 +501,11 @@ class VideoCourseList extends React.Component { ...@@ -499,9 +501,11 @@ class VideoCourseList extends React.Component {
)} )}
{this.state.shareLiveModal} {this.state.shareLiveModal}
{this.state.watchDataModal} {this.state.watchDataModal}
<Route path={`${match.url}/video-course-detail`} component={VideoCourseDetail} />
<Route path={`${match.url}/course-data`} component={WatchData} />
</div> </div>
); );
} }
} }
export default VideoCourseList; export default withRouter(VideoCourseList);
...@@ -24,11 +24,17 @@ ...@@ -24,11 +24,17 @@
} }
} }
} }
.chapterNum {
color: #2966ff;
cursor: pointer;
}
} }
} }
.watchUserCount { .watchUserCount {
text-align: right; text-align: right;
padding: 16px; padding: 16px;
color: #2966ff;
cursor: pointer;
} }
.operate-text { .operate-text {
color: #2966FF; color: #2966FF;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* @Date: 2020-08-05 10:12:15 * @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 16:07:27 * @LastEditTime: 2020-12-26 16:07:27
* @Description: 视频课-操作模块 * @Description: 线上课-操作模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -22,7 +22,7 @@ export default function VideoCourseOpt() { ...@@ -22,7 +22,7 @@ export default function VideoCourseOpt() {
RCHistory.push('/create-video-course?type=add'); RCHistory.push('/create-video-course?type=add');
}} }}
className="mr12" className="mr12"
>新建视频</Button> >新建线上</Button>
</div> </div>
); );
} }
import User from "@/common/js/user";
import college from "@/common/lottie/college";
import { PageControl, XMTable } from "@/components";
import Breadcrumbs from "@/components/Breadcrumbs";
import CourseService from "@/domains/course-domain/CourseService";
import { Input, Select } from "antd";
import React from "react";
import { withRouter } from "react-router-dom";
import LearningDetailModal from "./LearningDetailModal";
import "./WatchData.less";
const { Search } = Input;
class WatchData extends React.Component {
constructor(props) {
super(props);
const courseId = window.getParameterByName("courseId");
const courseName = window.getParameterByName("courseName");
this.state = {
courseName,
courseId,
visible: true,
dataSource: [],
query: {
current: 1,
size: 10,
sourceEnum: null,
},
totalCount: 0,
learningDetailModal: null,
};
}
componentDidMount() {
this.handleFetchDataList();
}
// 获取观看视频数据列表
handleFetchDataList = () => {
const { query, courseId } = this.state;
const params = {
...query,
courseId: courseId,
storeId: User.getStoreId(),
};
CourseService.videoWatchInfo(params).then((res) => {
const { result = {} } = res;
const { records = [], total = 0 } = result;
this.setState({
dataSource: records,
totalCount: Number(total),
});
});
};
parseColumns = () => {
const SOURCENUM = {
WE_CHAT: "微信",
WORK_WE_CHAT: "企业微信",
};
const columns = [
{
title: "观看学员",
key: "name",
dataIndex: "name",
render: (val, item) => {
return (
<div className="watcher">
<div className="watcher__name">{val}</div>
<div className={`watcher__type ${item.sourceEnum}`}>
@{SOURCENUM[item.sourceEnum]}
</div>
</div>
);
},
},
{
title: "手机号",
key: "phone",
dataIndex: "phone",
},
{
title: "首次观看时间",
key: "firstWatch",
dataIndex: "firstWatch",
render: (val) => {
return formatDate("YYYY-MM-DD H:i", val);
},
},
{
title: "学习进度",
key: "progress",
dataIndex: "progress",
render: (val) => {
return <span>{val}%</span>;
},
},
{
title: "操作",
key: "operate",
dataIndex: "operate",
render: (val, record) => {
return (
<div className="operate">
<div
className="operate__item"
onClick={() => this.ShowLearningDetailModal(record)}
>
学习详情
</div>
</div>
);
},
},
];
return columns;
};
// 显示学员数据详情弹窗
ShowLearningDetailModal = (item) => {
const learningDetailModal = (
<LearningDetailModal
data={item}
title="学习详情"
onClose={() => {
this.setState({
learningDetailModal: null
});
}}
courseId={this.state.courseId}
/>
);
this.setState({ learningDetailModal });
};
// 搜索学员姓名或手机号
handleChangNickname = (value) => {
const isPhone = (value || "").match(/^\d+$/);
const { query } = this.state;
let _query = { ...query };
if (isPhone) {
_query.phone = value;
_query.nickName = null;
} else {
_query.nickName = value;
_query.phone = null;
}
_query.current = 1;
this.setState(
{
query: _query,
},
this.handleFetchDataList
);
};
// 搜索学员类型
handleWatchTypeSelect = (sourceEnum) => {
const { query } = this.state;
let _query = { ...query };
_query.sourceEnum = sourceEnum;
this.setState(
{
query: _query,
},
this.handleFetchDataList
);
};
render() {
const { dataSource, totalCount, query, courseName } = this.state;
const { current, size, sourceEnum } = query;
return (
<div className="page video-course-watch-data">
<Breadcrumbs
navList="观看学员数据"
goBack={() => {
window.RCHistory.goBack();
}}
/>
<div className="box">
<div className="box-header">
<div className="course-detail">
<div className="detail__line"></div>
<div className="detail__name">{courseName}</div>
</div>
<div className="filter-box">
<div className="watcher-name">
<span className="label">学员:</span>
<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="watch-type">
<span className="label">学员类型:</span>
<Select
showSearch
style={{ width: 200 }}
allowClear
onPopupScroll={this.handleFetchMore}
placeholder="请选择学员类型"
value={sourceEnum}
onChange={this.handleWatchTypeSelect}
>
<Select.Option tyle={{ textAlign: "center" }} value="WE_CHAT">
微信
</Select.Option>
<Select.Option
tyle={{ textAlign: "center" }}
value="WORK_WE_CHAT"
>
企业微信
</Select.Option>
</Select>
</div>
</div>
</div>
<XMTable
renderEmpty={{
image: college,
description: "暂无数据",
}}
rowKey={(record) => record.id}
dataSource={dataSource}
columns={this.parseColumns()}
pagination={false}
bordered
className="video-list-table"
/>
<div className="box-footer">
<PageControl
current={current - 1}
pageSize={size}
total={totalCount}
toPage={(page) => {
const _query = { ...query, current: page + 1 };
this.setState(
{
query: _query,
},
() => {
this.handleFetchDataList();
}
);
}}
/>
</div>
</div>
{this.state.learningDetailModal}
</div>
);
}
}
export default withRouter(WatchData);
.video-course-watch-data {
.watcher {
display: flex;
&__type {
margin-left: 8px;
&.WE_CHAT {
color:rgba(28, 172, 27, 1);
}
&.WORK_WE_CHAT {
color: rgba(41, 102, 255, 1);
}
}
}
.filter-box {
display: flex;
margin-bottom: 4px;
.watcher-name {
margin-right: 40px;
}
}
.course-detail {
display: flex;
align-items: center;
margin-bottom: 16px;
.detail__line {
width: 4px;
height: 12px;
background-image: linear-gradient(#2966ff 83.5%, #0acca4 16.5%);
margin-right: 8px;
}
.detail__name {
width: 880px;
height: 26px;
font-size: 19px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
}
}
}
\ No newline at end of file
...@@ -15,18 +15,18 @@ class VideoCourse extends React.Component { ...@@ -15,18 +15,18 @@ class VideoCourse extends React.Component {
current: 1, current: 1,
storeId: User.getStoreId(), storeId: User.getStoreId(),
}, },
dataSource: [], // 视频课列表 dataSource: [], // 线上课列表
totalCount: 0, // 视频课数据总条数 totalCount: 0, // 线上课数据总条数
currentTabKey: 'internal', currentTabKey: 'internal',
}; };
} }
componentWillMount() { componentWillMount() {
// 获取视频课列表 // 获取线上课列表
this.handleFetchScheduleList(); this.handleFetchScheduleList();
} }
// 获取视频课列表 // 获取线上课列表
handleFetchScheduleList = (_query = {}) => { handleFetchScheduleList = (_query = {}) => {
const { currentTabKey } = this.state; const { currentTabKey } = this.state;
const query = { const query = {
...@@ -81,7 +81,7 @@ class VideoCourse extends React.Component { ...@@ -81,7 +81,7 @@ class VideoCourse extends React.Component {
const { dataSource, totalCount, query, currentTabKey } = this.state; const { dataSource, totalCount, query, currentTabKey } = this.state;
return ( return (
<div className='page video-course-page'> <div className='page video-course-page'>
<div className='content-header'>视频</div> <div className='content-header'>线上</div>
<div className='box'> <div className='box'>
<Tabs onChange={this.currenTabChange} activeKey={currentTabKey}> <Tabs onChange={this.currenTabChange} activeKey={currentTabKey}>
...@@ -95,7 +95,7 @@ class VideoCourse extends React.Component { ...@@ -95,7 +95,7 @@ class VideoCourse extends React.Component {
<If condition={currentTabKey === 'internal'}> <If condition={currentTabKey === 'internal'}>
<VideoCourseOpt /> <VideoCourseOpt />
</If> </If>
{/* 视频课列表模块 */} {/* 线上课列表模块 */}
<VideoCourseList <VideoCourseList
type={currentTabKey} type={currentTabKey}
query={query} query={query}
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* @Date: 2020-05-19 11:01:31 * @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁 * @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47 * @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗 * @Description 学员观看数据弹窗
*/ */
import User from '@/common/js/user'; import User from '@/common/js/user';
import { PageControl, XMTable } from '@/components'; import { PageControl, XMTable } from '@/components';
...@@ -128,65 +128,52 @@ class WatchDataModal extends React.Component { ...@@ -128,65 +128,52 @@ class WatchDataModal extends React.Component {
const { visible, size, dataSource, totalCount, query } = this.state; const { visible, size, dataSource, totalCount, query } = this.state;
return ( return (
<Modal <Modal
title='视频课观看数据' title="线上课观看数据"
visible={visible} visible={visible}
footer={null} footer={null}
onCancel={this.onClose} onCancel={this.onClose}
maskClosable={false} maskClosable={false}
className='watch-data-modal' className="watch-data-modal"
closable={true} closable={true}
width={800} width={800}
closeIcon={<span className='icon iconfont modal-close-icon'>&#xe6ef;</span>}> closeIcon={<span className="icon iconfont modal-close-icon">&#xe6ef;</span>}
<div className='search-container'> >
<Search <div className="search-container">
placeholder='搜索学员姓名/手机号' <Search placeholder="搜索学员姓名/手机号" style={{ width: 200 }} onChange={(e) => { this.handleChangNickname(e.target.value)}} onSearch={ () => { this.handleFetchDataList()}} enterButton={<span className="icon iconfont">&#xe832;</span>}/>
style={{ width: 200 }}
onChange={(e) => {
this.handleChangNickname(e.target.value);
}}
onSearch={() => {
this.handleFetchDataList();
}}
enterButton={<span className='icon iconfont'>&#xe832;</span>}
/>
</div> </div>
<div> <div>
<XMTable <XMTable
renderEmpty={{ renderEmpty={{
image: college, image: college,
description: '暂无数据', description: '暂无数据',
}} }}
rowKey={(record) => record.id} rowKey={record => record.id}
dataSource={dataSource} dataSource={dataSource}
columns={this.parseColumns()} columns={this.parseColumns()}
pagination={false} pagination={false}
bordered bordered
/> />
{dataSource.length > 0 && ( {dataSource.length >0 &&
<div className='box-footer'> <div className="box-footer">
<PageControl <PageControl
current={query.current - 1} current={query.current - 1}
pageSize={size} pageSize={size}
total={totalCount} total={totalCount}
size='small' size="small"
toPage={(page) => { toPage={(page) => {
const _query = { ...query, current: page + 1 }; const _query = {...query, current: page + 1};
this.setState( this.setState({
{ query:_query
query: _query, },()=>{ this.handleFetchDataList()})
},
() => {
this.handleFetchDataList();
}
);
}} }}
onShowSizeChange={this.onShowSizeChange} onShowSizeChange={this.onShowSizeChange}
/> />
</div> </div>
)} }
</div> </div>
</Modal> </Modal>
); )
} }
} }
......
import Service from '@/common/js/service'; import React, { useEffect, useState } from 'react';
import User from '@/common/js/user'; import { Select, Tooltip, Carousel, Popover } from 'antd';
import DataSet from '@antv/data-set'; import DataSet from "@antv/data-set";
import { Chart as G2Chart } from '@antv/g2'; import { Chart as G2Chart } from '@antv/g2';
import { Select, Tooltip } from 'antd'; import {
import { Axis, Chart, Coord, Geom, Guide, Tooltip as G2Tooltip } from 'bizcharts'; G2,
import moment from 'moment'; Chart,
import React from 'react'; Geom,
Axis,
Tooltip as G2Tooltip,
Coord,
Label,
Legend,
View,
Guide,
Shape,
Facet,
Util
} from "bizcharts";
import moment from 'moment'
import Service from "@/common/js/service";
import User from '@/common/js/user';
import HomeTip from './HomeTip';
import './Home.less'; import './Home.less';
import HomeTip from './HomeTip'; import HomeTip from './HomeTip';
...@@ -328,7 +344,7 @@ class Home extends React.Component { ...@@ -328,7 +344,7 @@ class Home extends React.Component {
</div> </div>
</div> </div>
<div className='course-item'> <div className='course-item'>
<div className='course-title'>视频</div> <div className='course-title'>线上</div>
<div className='data'> <div className='data'>
<span className='course-number'>{videoCourseNum}</span> <span className='course-number'>{videoCourseNum}</span>
{incVideoCourseNum > 0 && <span className='icon iconfont'>&#xe635;</span>} {incVideoCourseNum > 0 && <span className='icon iconfont'>&#xe635;</span>}
...@@ -394,9 +410,8 @@ class Home extends React.Component { ...@@ -394,9 +410,8 @@ class Home extends React.Component {
</span> </span>
<span <span
className={`tab${scheduleType === 'VOICE' ? ' selected' : ''}`} className={`tab${scheduleType === 'VOICE' ? ' selected' : ''}`}
onClick={() => this.setState({ scheduleType: 'VOICE' }, () => this.getHotCourse())}> onClick={() => this.setState({ scheduleType: 'VOICE' }, () => this.getHotCourse())}
视频课 >线上课</span>
</span>
<span <span
className={`tab${scheduleType === 'PICTURE' ? ' selected' : ''}`} className={`tab${scheduleType === 'PICTURE' ? ' selected' : ''}`}
onClick={() => this.setState({ scheduleType: 'PICTURE' }, () => this.getHotCourse())}> onClick={() => this.setState({ scheduleType: 'PICTURE' }, () => this.getHotCourse())}>
......
...@@ -106,6 +106,7 @@ ...@@ -106,6 +106,7 @@
font-size: 16px; font-size: 16px;
font-family: 'number'; font-family: 'number';
margin-right: 16px; margin-right: 16px;
white-space: nowrap;
} }
.course-word { .course-word {
font-size: 12px; font-size: 12px;
...@@ -120,6 +121,7 @@ ...@@ -120,6 +121,7 @@
.add-number { .add-number {
font-size: 12px; font-size: 12px;
color: #999; color: #999;
white-space: nowrap;
} }
} }
} }
......
...@@ -55,7 +55,7 @@ const ENUM = { ...@@ -55,7 +55,7 @@ const ENUM = {
CourseTypeEnum: { CourseTypeEnum: {
LIVE: "直播课", LIVE: "直播课",
VOICE: "视频课", VOICE: "线上课",
PICTURE: "图文课", PICTURE: "图文课",
FOLDER: "学习资料", FOLDER: "学习资料",
}, },
......
...@@ -188,7 +188,7 @@ class Classification extends Component { ...@@ -188,7 +188,7 @@ class Classification extends Component {
<div className='sider-title'>知识分类</div> <div className='sider-title'>知识分类</div>
<Search <Search
className='sider-search' className='sider-search'
placeholder='搜索名称分类' placeholder='搜索分类名称'
onSearch={(value) => { onSearch={(value) => {
this.queryCategoryTree(value); this.queryCategoryTree(value);
}} }}
......
...@@ -65,10 +65,11 @@ class KnowledgeBaseFilter extends React.Component { ...@@ -65,10 +65,11 @@ class KnowledgeBaseFilter extends React.Component {
<Row type="flex" justify="space-between" align="top"> <Row type="flex" justify="space-between" align="top">
<div className="search-condition"> <div className="search-condition">
<div className="search-condition__item"> <div className="search-condition__item">
<span className="search-name">课程名称:</span> <span className="search-name">资料名称:</span>
<Search <Search
value={name} value={name}
placeholder="搜索课程名称" // allowClear
placeholder="搜索资料名称"
onChange={(e) => { onChange={(e) => {
this.handleChangeQuery("name", e.target.value, false); this.handleChangeQuery("name", e.target.value, false);
}} }}
...@@ -79,33 +80,6 @@ class KnowledgeBaseFilter extends React.Component { ...@@ -79,33 +80,6 @@ class KnowledgeBaseFilter extends React.Component {
enterButton={<span className="icon iconfont">&#xe832;</span>} enterButton={<span className="icon iconfont">&#xe832;</span>}
/> />
</div> </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>
<div className="reset-fold-area"> <div className="reset-fold-area">
<Tooltip title="清空筛选"> <Tooltip title="清空筛选">
......
...@@ -3,12 +3,13 @@ ...@@ -3,12 +3,13 @@
* @Author: zangsuyun * @Author: zangsuyun
* @Date: 2021-03-12 14:49:40 * @Date: 2021-03-12 14:49:40
* @LastEditors: Please set LastEditors * @LastEditors: Please set LastEditors
* @LastEditTime: 2021-06-11 16:44:59 * @LastEditTime: 2021-07-13 15:28:04
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有 * @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/ */
import React from "react"; import React from "react";
import { Modal, message, Tooltip, Switch, Dropdown, Button } from "antd"; import { Modal, message, Tooltip, Switch, Dropdown, Button } from "antd";
import { FileTypeIcon, FileVerifyMap } from '@/common/constants/academic/lessonEnum';
import { Route, withRouter } from "react-router-dom"; import { Route, withRouter } from "react-router-dom";
import { PageControl, XMTable } from "@/components"; import { PageControl, XMTable } from "@/components";
import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass"; import { LIVE_SHARE_MAP } from "@/common/constants/academic/cloudClass";
...@@ -181,161 +182,20 @@ class KnowledgeBaseList extends React.Component { ...@@ -181,161 +182,20 @@ class KnowledgeBaseList extends React.Component {
const { current, size } = query const { current, size } = query
const columns = [ const columns = [
{ {
title: "课程名称", title: "名称",
key: "name", key: "name",
dataIndex: "name", dataIndex: "name",
width: 391,
fixed: "left",
render: (val, record) => { render: (val, record) => {
const { coverUrl, mediaCourseUrl, courseDivision } = record.source const { coverUrl, mediaCourseUrl, courseDivision } = record.source
let hasCover = false let hasCover = false
const type = record.type const type = record.type
return ( return (
<div>
{type === "LIVE" && (
<div className='record__item'>
{record.source &&
record.source.courseMediaVOS.map((item, index) => {
if (item.contentType === "COVER") {
hasCover = true
return <img className='course-cover' key={index} src={item.mediaUrl} />
}
})}
{!hasCover && (
<img
className="course-cover"
src={"https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png"}
/>
)}
<div>
{val.length > 17 ? (
<Tooltip title={val}>
<div className='course-name'>{val}</div>
</Tooltip>
) : (
<div className='course-name'>{val}</div>
)}
<div>
<span className='course-time'>
{formatDate("YYYY-MM-DD H:i", parseInt(record.source.startTime))}~{formatDate("H:i", parseInt(record.source.endTime))}
</span>
<span
className='course-status'
style={{
color: ENUM.courseStateShow[record.source.courseState].color,
border: `1px solid ${ENUM.courseStateShow[record.source.courseState].color}`
}}>
{ENUM.courseStateShow[record.source.courseState].title}
</span>
{record.hideToUser && (
<Tooltip title={<div>课程未成功开课,已在学员知识列表中隐藏</div>}>
<i
className='icon iconfont'
style={{
marginLeft: "5px",
cursor: "pointer",
color: "#FF4F4F",
fontSize: "14px"
}}>
&#xe61d;
</i>
</Tooltip>
)}
</div>
<div className='teacher-assistant'>
{record.source.teacherName.length > 4 ? (
<Tooltip title={record.source.teacherName}>
<span className='teacher'>讲师:{record.source.teacherName}</span>
</Tooltip>
) : (
<span className='teacher'>讲师:{record.source.teacherName}</span>
)}
{record.source.admins.length > 0 && (
<>
<span className='split'> | </span>
{this.handleAdminName(record.source.admins).length > 4 ? (
<Tooltip title={this.handleAdminName(record.source.admins)}>
<span className='assistant'>
助教:
{record.source.admins.map((item, index) => {
return (
<span>
{item.adminName} {index < record.source.admins.length - 1 && <span></span>}{" "}
</span>
)
})}
</span>
</Tooltip>
) : (
<span className='assistant'>
助教:
{record.source.admins.map((item, index) => {
return (
<span key={index}>
{item.adminName} {index < record.source.admins.length - 1 && <span></span>}{" "}
</span>
)
})}
</span>
)}
</>
)}
</div>
</div>
</div>
)}
{type === "VOICE" && (
<div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img
className='course-cover'
src={
coverUrl
? coverUrl
: courseDivision !== "EXTERNAL"
? `${mediaCourseUrl}?x-oss-process=video/snapshot,t_0,m_fast`
: "https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png"
}
alt=''
/>
{val.length > 25 ? (
<Tooltip title={val}>
<div className='course-name clamp'>{val}</div>
</Tooltip>
) : (
<div className='course-name clamp'>{val}</div>
)}
</div>
)}
{type === "PICTURE" && (
<div className="record__item">
<img
className="course-cover"
src={
coverUrl ||
"https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png"
}
/>
{val.length > 25 ? (
<Tooltip title={val}>
<div className='course-name clamp'>{val}</div>
</Tooltip>
) : (
<div className='course-name clamp'>{val}</div>
)}
</div>
)}
{type === "FOLDER" && (
<div <div
className='record__item' className='record__item'
onClick={() => { onClick={() => {
this.handleScanFile(record.source) this.handleScanFile(record.source)
}}> }}>
<div className={`folder-type ${record.source && record.source.folderFormat}`} /> <img src={FileTypeIcon[record.source.folderFormat] } style={{width:24,height:24}} alt='' className='item-img' />
{val.length > 25 ? ( {val.length > 25 ? (
<Tooltip title={val}> <Tooltip title={val}>
<div className='course-name clamp'>{val}</div> <div className='course-name clamp'>{val}</div>
...@@ -344,22 +204,11 @@ class KnowledgeBaseList extends React.Component { ...@@ -344,22 +204,11 @@ class KnowledgeBaseList extends React.Component {
<div className='course-name clamp'>{val}</div> <div className='course-name clamp'>{val}</div>
)} )}
</div> </div>
)}
</div>
) )
} }
}, },
{ {
title: "课程类型",
key: "type",
dataIndex: "type",
align: "center",
// width: 100,
render: (val, record) => {
return <div className=''>{val ? ENUM.CourseTypeEnum[val] : "-"}</div>
}
},
{
title: "创建人", title: "创建人",
key: "createName", key: "createName",
dataIndex: "createName", dataIndex: "createName",
...@@ -393,7 +242,7 @@ class KnowledgeBaseList extends React.Component { ...@@ -393,7 +242,7 @@ class KnowledgeBaseList extends React.Component {
}, },
{ {
title: "", title: "",
width: 48
}, },
{ {
title: "操作", title: "操作",
...@@ -452,7 +301,6 @@ class KnowledgeBaseList extends React.Component { ...@@ -452,7 +301,6 @@ class KnowledgeBaseList extends React.Component {
const { match } = this.props; const { match } = this.props;
localStorage.setItem("WatchData_CourseName", item.name); localStorage.setItem("WatchData_CourseName", item.name);
window.RCHistory.push({ window.RCHistory.push({
// pathname: `${match.url}/course-data?type=${item.courseType}&id=${item.liveCourseId}`,
pathname: `${match.url}/course-data?type=${item.type}&id=${item.id}` pathname: `${match.url}/course-data?type=${item.type}&id=${item.id}`
}) })
} }
...@@ -501,7 +349,7 @@ class KnowledgeBaseList extends React.Component { ...@@ -501,7 +349,7 @@ class KnowledgeBaseList extends React.Component {
dataSource={dataSource} dataSource={dataSource}
columns={this.parseColumns()} columns={this.parseColumns()}
pagination={false} pagination={false}
scroll={{ x: 900 }}
bordered bordered
className="knowledge-list-table" className="knowledge-list-table"
renderEmpty={{ renderEmpty={{
......
...@@ -109,7 +109,10 @@ ...@@ -109,7 +109,10 @@
.knowledge-base-list { .knowledge-base-list {
.record__item { .record__item {
display: flex; display: flex;
// align-items: center; align-items: center;
.item-img{
margin-right: 4px;
}
.course-cover { .course-cover {
min-width: 107px; min-width: 107px;
max-width: 90px; max-width: 90px;
...@@ -153,13 +156,7 @@ ...@@ -153,13 +156,7 @@
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
height: 20px; height: 20px;
&.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
white-space: normal;
height: 40px;
}
} }
.course-time { .course-time {
font-size: 12px; font-size: 12px;
......
...@@ -9,10 +9,8 @@ ...@@ -9,10 +9,8 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import { Button, Menu, Dropdown,message, Modal } from "antd"; import { Button, Menu, Dropdown, message, Modal } from "antd";
import SelectPrepareFileModal from "@/modules/prepare-lesson/modal/SelectPrepareFileModal"; 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 User from "@/common/js/user";
import Service from "@/common/js/service"; import Service from "@/common/js/service";
import KnowledgeAPI from "@/data-source/knowledge/request-api"; import KnowledgeAPI from "@/data-source/knowledge/request-api";
...@@ -31,16 +29,7 @@ export default function KnowledgeBaseOpt({ ...@@ -31,16 +29,7 @@ export default function KnowledgeBaseOpt({
const [openMoveModal, setOpenMoveModal] = useState(false); const [openMoveModal, setOpenMoveModal] = useState(false);
const [data, setData] = useState([]); const [data, setData] = useState([]);
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>
);
useEffect(() => { useEffect(() => {
queryCategoryTree(); queryCategoryTree();
...@@ -76,19 +65,6 @@ export default function KnowledgeBaseOpt({ ...@@ -76,19 +65,6 @@ export default function KnowledgeBaseOpt({
return newTreeData; return newTreeData;
}; };
function handAddCourse() {
let modal = (
<AddCourse
onClose={() => {
setModal(null);
}}
onChange={onChange}
categoryId={categoryId}
updateCategoryTree={updateCategoryTree}
></AddCourse>
);
setModal(modal);
}
function handUpload(refIds) { function handUpload(refIds) {
const params = { const params = {
...@@ -118,7 +94,7 @@ export default function KnowledgeBaseOpt({ ...@@ -118,7 +94,7 @@ export default function KnowledgeBaseOpt({
isOpen={true} isOpen={true}
accept=".ppt,.pptx,.doc,.docx,.pdf,.jpg,.jpeg,.png,.xlsx,.xls" accept=".ppt,.pptx,.doc,.docx,.pdf,.jpg,.jpeg,.png,.xlsx,.xls"
tooltip="支持文件类型:ppt、word、excel、pdf、jpg、jpeg、png" 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 selectTypeList={["JPG", "JPEG", "PNG", 'DOC', 'PDF', 'EXCEL', 'application/msword', 'application/vnd.ms-powerpoint']} // DOC 包含 .pptx,.docx,.xls.XLSX,WORD:DOC
onClose={() => { onClose={() => {
setModal(null); setModal(null);
}} }}
...@@ -205,12 +181,9 @@ export default function KnowledgeBaseOpt({ ...@@ -205,12 +181,9 @@ export default function KnowledgeBaseOpt({
return ( return (
<div className="knowledge-course-opt"> <div className="knowledge-course-opt">
{_.isEmpty(selectedRowKeys) ? {_.isEmpty(selectedRowKeys) ?
(categoryId !== '0' && <Dropdown overlay={menu}> categoryId !== '0' && <Button type="primary" onClick={handleAddFile} className="mr8">
<Button type="primary" className="mr8"> 添加资料
添加知识
<DownOutlined />
</Button> </Button>
</Dropdown>)
: <div className="select-container"> : <div className="select-container">
<span className="con"> <span className="con">
<div> <div>
......
...@@ -107,11 +107,11 @@ class AddCourse extends React.Component { ...@@ -107,11 +107,11 @@ class AddCourse extends React.Component {
selectVideo: { selectVideo: {
external: [], external: [],
internal: [], internal: [],
}, //弹窗内已选择的视频课程 }, //弹窗内已选择的线上课程
currentVideoCourseListData: { currentVideoCourseListData: {
external: [], external: [],
internal: [], internal: [],
}, //页面中已关联的视频课程 }, //页面中已关联的线上课程
pictureDataSource: [], pictureDataSource: [],
pictureSize: 10, pictureSize: 10,
...@@ -201,7 +201,7 @@ class AddCourse extends React.Component { ...@@ -201,7 +201,7 @@ class AddCourse extends React.Component {
}); });
}; };
// 获取视频课列表 // 获取线上课列表
handleFetchVideoList = () => { handleFetchVideoList = () => {
const { videoQuery, videoSize, videoCourseDivision, videoDataSource, videoTotalCount } = this.state; const { videoQuery, videoSize, videoCourseDivision, videoDataSource, videoTotalCount } = this.state;
...@@ -421,7 +421,7 @@ class AddCourse extends React.Component { ...@@ -421,7 +421,7 @@ class AddCourse extends React.Component {
coverUrl || coverUrl ||
(videoCourseDivision === 'internal' (videoCourseDivision === 'internal'
? `${mediaCourseUrl}?x-oss-process=video/snapshot,t_0,m_fast` ? `${mediaCourseUrl}?x-oss-process=video/snapshot,t_0,m_fast`
: 'https://image.xiaomaiketang.com/xm/mt3ZQRxGKB.png') : 'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png')
} }
alt='' alt=''
/> />
...@@ -866,7 +866,7 @@ class AddCourse extends React.Component { ...@@ -866,7 +866,7 @@ class AddCourse extends React.Component {
)} )}
</div> </div>
</TabPane> </TabPane>
<TabPane tab='视频课' key='VIDEO'> <TabPane tab='线上课' key='VIDEO'>
<Radio.Group value={videoCourseDivision} onChange={this.videoCourseDivisionChange} style={{ marginBottom: 8 }}> <Radio.Group value={videoCourseDivision} onChange={this.videoCourseDivisionChange} style={{ marginBottom: 8 }}>
<Radio.Button value='internal'>内部课程</Radio.Button> <Radio.Button value='internal'>内部课程</Radio.Button>
<Radio.Button value='external'>外部课程</Radio.Button> <Radio.Button value='external'>外部课程</Radio.Button>
......
...@@ -25,7 +25,7 @@ class VideoList extends React.Component { ...@@ -25,7 +25,7 @@ class VideoList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
id: "", // 视频课ID id: "", // 线上课ID
studentIds: [], studentIds: [],
selectedRowKeys: [], selectedRowKeys: [],
query: { query: {
...@@ -33,8 +33,8 @@ class VideoList extends React.Component { ...@@ -33,8 +33,8 @@ class VideoList extends React.Component {
current: 1, current: 1,
storeId: User.getStoreId(), storeId: User.getStoreId(),
}, },
dataSource: [], // 视频课列表 dataSource: [], // 线上课列表
totalCount: 0, // 视频课数据总条数 totalCount: 0, // 线上课数据总条数
}; };
} }
...@@ -50,11 +50,11 @@ class VideoList extends React.Component { ...@@ -50,11 +50,11 @@ class VideoList extends React.Component {
} }
componentWillMount() { componentWillMount() {
// 获取视频课列表 // 获取线上课列表
this.handleFetchScheduleList(); this.handleFetchScheduleList();
} }
// 获取视频课列表 // 获取线上课列表
handleFetchScheduleList = (_query = {}) => { handleFetchScheduleList = (_query = {}) => {
const query = { const query = {
...this.state.query, ...this.state.query,
......
.plan-basic-info{ .plan-basic-info {
.label { .label {
width: 110px; width: 110px;
text-align: right; text-align: right;
display:inline-block; display: inline-block;
font-size:14px; font-size: 14px;
color:#666; color: #666;
.require { .require {
color: #EC4B35; color: #ec4b35;
} }
.iconfont{ .iconfont {
font-size:14px; font-size: 14px;
color:#BFBFBF; color: #bfbfbf;
} }
} }
.cover { .cover {
display: flex; display: flex;
margin-top: 16px; margin-top: 24px;
&__wrap { &__wrap {
position: relative; position: relative;
display: flex;
.tag { .tag {
border-radius: 2px; border-radius: 2px;
background: #D6D6D6; background: #d6d6d6;
font-size: 12px; font-size: 12px;
height: 18px; height: 18px;
width: 52px; width: 52px;
text-align: center; text-align: center;
color: #FFF; color: #fff;
position: absolute; position: absolute;
top: 8px; top: 8px;
left: 8px; left: 8px;
} }
} }
.img-content { .img-content {
margin-right: 20px; position: relative;
margin-top: 8px;
width: 299px; width: 299px;
height: 169px; height: 169px;
img { img {
...@@ -42,90 +42,93 @@ ...@@ -42,90 +42,93 @@
object-fit: contain; object-fit: contain;
} }
} }
.opt-btns{ .opt-btns {
.default-btn { .default-btn {
margin:0 8px; margin-left: 14px;
color: #2966FF; color: #2966ff;
cursor: pointer; cursor: pointer;
&.disabled { &.disabled {
color: #CCC; color: #ccc;
cursor: not-allowed; cursor: not-allowed;
} }
} }
.tips{ .tips {
margin-top:8px; margin-top: 8px;
font-size:14px; font-size: 14px;
color:#999; color: #999;
} }
} }
} }
.introduction{ .introduction {
margin-top:16px; display: flex;
.instro-textarea{ margin-top: 24px;
.instro-textarea {
vertical-align: top; vertical-align: top;
} }
} }
.wether-use{ .wether-use {
display:flex; display: flex;
margin-top:16px; margin-top: 34px;
.instro-text{ .instro-text {
color:#999; color: #999;
margin-left:12px; margin-left: 12px;
} }
.content{ .content {
display:flex; display: flex;
} }
} }
.view-range{ .view-range {
display:flex; display: flex;
margin-top:16px; margin-top: 24px;
.label{ .label {
margin-top:2px; margin-top: 2px;
} }
.instro-text{ .instro-text {
color:#999; color: #999;
margin-left:12px; margin-left: 12px;
} }
.choose-business{ .choose-business {
margin-top:16px; margin-top: 12px;
.ant-btn {
margin-right: 12px;
} }
.playback__text{
margin-left:12px;
color:#999999;
} }
.playback__text {
margin-left: 12px;
color: #999999;
} }
.done-standard{ }
.done-standard {
display: flex; display: flex;
margin-top:22px; margin-top: 22px;
.standard-label{ .standard-label {
margin-top:3px; margin-top: 3px;
} }
.live-standard-info{ .live-standard-info {
margin-bottom:10px; margin-bottom: 10px;
} }
input{ input {
display:inline-block; display: inline-block;
width:90px; width: 90px;
height:32px; height: 32px;
} }
.icon{ .icon {
color:#A0A0A0; color: #a0a0a0;
font-size:14px; font-size: 14px;
margin-right:4px; margin-right: 4px;
} }
.instro{ .instro {
color:#333333; color: #333333;
font-size:14px; font-size: 14px;
} }
.input-box{ .input-box {
width: 60px; width: 60px;
height: 32px; height: 32px;
border-radius: 4px; border-radius: 4px;
border: 1px solid #E8E8E8; border: 1px solid #e8e8e8;
color:#333333; color: #333333;
font-size:14px; font-size: 14px;
margin:0 2px; margin: 0 2px;
} }
} }
} }
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