Commit 5bd7d0b0 by maolipeng

Merge branch 'feature/zhujian/0726/qwLiving' into rc

# Conflicts:
#	src/common/js/platform.js
#	src/common/js/wechatApi.js
#	src/index.html
#	src/index.tsx
#	src/modules/course-manage/components/AddLiveBasic.jsx
#	src/modules/course-manage/components/LiveCourseList.jsx
#	src/modules/root/App.tsx
parents 3614abf9 e131b7ae
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -96,6 +96,12 @@ class Axios { ...@@ -96,6 +96,12 @@ class Axios {
content: `当前企业购买的${window.brandName}服务已到期,如需继续使用学院功能,请尽快续费购买`, content: `当前企业购买的${window.brandName}服务已到期,如需继续使用学院功能,请尽快续费购买`,
okText: "我知道了" okText: "我知道了"
}) })
} else if (resultCode === "LIVE_START_FORBID_DEL") {
Modal.warning({
title:"提示",
content: "直播进行中,无法删除直播",
okText: "我知道了"
})
} else if (success || resultCode === 0) { } else if (success || resultCode === 0) {
return response; return response;
} else if (!options.reject) { } else if (!options.reject) {
......
...@@ -40,4 +40,4 @@ module.exports = { ...@@ -40,4 +40,4 @@ module.exports = {
return /xmappc/i.test(ua); return /xmappc/i.test(ua);
}, },
}; };
\ No newline at end of file
...@@ -14,57 +14,56 @@ import Service from '@/common/js/service'; ...@@ -14,57 +14,56 @@ import Service from '@/common/js/service';
export default class WechatApi { export default class WechatApi {
static async initConfig(params = { isAgentConfig: false, url: '' }) { static async initConfig(params = { isAgentConfig: false, url: '' }) {
if (Platform.isWorkWx()) { if(Platform.isWorkWx()){
return Service.Hades('anon/hades/getWxCorpJSAPISignature', {
return new Promise(async (resolve, reject) => { storeId: User.getStoreId(),
Service.Hades('anon/hades/getWxCorpJSAPISignature', { url: params.url,
storeId: User.getStoreId(), }).then((result) => {
url: params.url, const res = result.result;
}).then((result) => { this.config({
const res = result.result; beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题
this.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
beta: true, // 必须这么写,否则wx.invoke调用形式的jsapi会有问题 appId: res.appId, // 必填,企业微信的corpID
debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 timestamp: res.timestamp, // 必填,生成签名的时间戳
appId: res.appId, // 必填,企业微信的corpID nonceStr: res.nonceStr, // 必填,生成签名的随机串
timestamp: res.timestamp, // 必填,生成签名的时间戳 signature: res.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法
nonceStr: res.nonceStr, // 必填,生成签名的随机串 jsApiList: ['chooseImage', 'shareToExternalContact', 'selectExternalContact', 'selectEnterpriseContact'],
signature: res.signature, // 必填,签名,见 附录-JS-SDK使用权限签名算法 }).then(() => {
jsApiList: ['chooseImage', 'shareToExternalContact', 'selectExternalContact', 'selectEnterpriseContact'], if (params.isAgentConfig) {
}).then(() => { return new Promise(async (resolve, reject) => {
Service.Hades('anon/hades/getWxWorkJSAPISignature', { Service.Hades('anon/hades/getWxWorkJSAPISignature', {
storeId: User.getStoreId(), storeId: User.getStoreId(),
url: params.url, url: params.url,
}).then((result2) => { }).then((result2) => {
const res2 = result2.result; const res2 = result2.result;
this.agentConfig({ this.agentConfig({
corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致 corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247) agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res2.timestamp, // 必填,生成签名的时间戳 timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串 nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法 signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat'], jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat', 'startLiving', 'replayLiving'],
success: (res) => { success: (res) => {
console.log(res, 'res-agentconfig'); console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData); console.info('window.WWOpenData', window.WWOpenData);
resolve(res); resolve(res);
}, },
fail: (err) => { fail: (err) => {
console.log(1213545344545) console.log(1213545344545)
console.log(err, 'err-agentconfig'); console.log(err, 'err-agentconfig');
reject(err); reject(err);
}, },
});
}); });
}); });
}
}) })
}); });
}) }else{
} else {
if (params.isAgentConfig) { if (params.isAgentConfig) {
console.log(32132132, 'cesgu') console.log(32132132,'cesgu')
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
Service.Hades('anon/hades/getWxWorkJSAPISignature', { Service.Hades('anon/hades/getWxWorkJSAPISignature', {
storeId: User.getStoreId(), storeId: User.getStoreId(),
...@@ -77,7 +76,7 @@ export default class WechatApi { ...@@ -77,7 +76,7 @@ export default class WechatApi {
timestamp: res2.timestamp, // 必填,生成签名的时间戳 timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串 nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法 signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat'], jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat', 'startLiving', 'replayLiving'],
success: (res) => { success: (res) => {
console.log(res, 'res-agentconfig'); console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData); console.info('window.WWOpenData', window.WWOpenData);
...@@ -93,7 +92,7 @@ export default class WechatApi { ...@@ -93,7 +92,7 @@ export default class WechatApi {
}); });
} }
} }
} }
static async config(config) { static async config(config) {
...@@ -114,7 +113,19 @@ export default class WechatApi { ...@@ -114,7 +113,19 @@ export default class WechatApi {
} }
static async agentConfig(config) { static async agentConfig(config) {
wx.agentConfig({ ...config }); return new Promise((success, fail) => {
console.info('wx.agentConfig', config);
wx.agentConfig({ ...config, success, fail });
}).then(
(res) => {
console.info('wx.agentConfig success', res);
return res;
},
(error) => {
console.error('wx.agentConfig fail', error);
throw error;
}
);
} }
static getCurExternalContact() { static getCurExternalContact() {
...@@ -144,4 +155,53 @@ export default class WechatApi { ...@@ -144,4 +155,53 @@ export default class WechatApi {
}); });
}); });
} }
//进入直播间
static enterLiveRoom(id) {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke('startLiving', {
"livingId": id,
}, function(res) {
if (res.err_msg === "startLiving:ok") {
resolve(true)
} else {
reject(res.err_msg); //错误处理
}
});
});
})
}
static replayLiving(id) {
return new Promise((resolve, reject) => {
wx.ready(() => {
wx.invoke('replayLiving', {
"livingId": id,
}, function(res) {
if (res.err_msg === "replayLiving:ok") {
resolve(true)
} else {
let err = "进入回放失败"
console.log(res.err_msg);
if (res.err_msg === "replayLiving:fail_invalid living id") {
err = "不合法的直播ID"
} else if (res.err_msg === "replayLiving:fail_not allow to cross corp") {
err = "不可跨企业使用直播ID"
} else if (res.err_msg === "replayLiving:fail_not allow to cross app") {
err = "不可跨应用使用直播ID"
} else if (res.err_msg === "replayLiving:fail_living has no replay") {
// err = "直播回放已失效或不存在"
err = "该直播课未录制回放"
} else if (res.err_msg === "replayLiving:fail_replay is beging creating") {
err = "回放生成中,请耐心等待"
} else if (res.err_msg === "replayLiving:fail_create replay failed") {
err = "回放创建失败"
} else if (res.err_msg === "replayLiving:fail_invalid parameter") {
err = "参数不合法"
}
reject(err); //错误处理
}
});
});
})
}
} }
...@@ -330,9 +330,9 @@ mr0 { ...@@ -330,9 +330,9 @@ mr0 {
} }
// ant badge改小 // ant badge改小
.ant-badge { // .ant-badge {
transform: translate(-8px, -8px) scale(0.7) !important; // transform: translate(-8px, -8px) scale(0.7) !important;
} // }
.ant-select-selection { .ant-select-selection {
border-color: @xm-color-border !important; border-color: @xm-color-border !important;
......
...@@ -1698,4 +1698,24 @@ input:focus { ...@@ -1698,4 +1698,24 @@ input:focus {
.ant-tag-blue{ .ant-tag-blue{
background: transparent !important; background: transparent !important;
}
.createQWCourse{
.footer {
position: fixed;
bottom: 0;
height: 58px;
width: 100%;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 252px;
background: #fff;
border-top: 1px solid #E8E8E8;
z-index: 999;
.ant-btn {
margin-left: 10px;
}
}
} }
\ No newline at end of file
module.exports = {
isWeiXin() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('micromessenger') > 0;
},
isWorkWx (){
return /wxwork/i.test(navigator.userAgent)
},
isAlipay() {
const ua = navigator.userAgent.toLowerCase();
return ua.indexOf('aliapp') > 0 || ua.indexOf('alipay') > 0;
},
isXiaoMaiApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios' || ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isXiaoMaiIOSApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_ios/i) === 'xiaomai_ios';
},
isXiaoMaiAndroidApp() {
const ua = navigator.userAgent.toLowerCase();
return ua.match(/xiaomai_android/i) === 'xiaomai_android';
},
isAndroid() {
const ua = navigator.userAgent.toLowerCase();
return /android/i.test(ua);
},
isIOS() {
const ua = navigator.userAgent.toLowerCase();
return /iphone|ipad|ipod/i.test(ua);
},
isMeiKe() {
const ua = navigator.userAgent.toLowerCase();
return /xmappc/i.test(ua);
},
};
\ No newline at end of file
import Bus from './bus';
class routeHook {
constructor() {
this.routeFun = [];
this.callBacks = []
}
add(callback) { //切换路由之前添加的函数
this.routeFun = [callback]
}
addJump(callback) {
this.callBacks = [callback]
}
pop() { //去除回调
this.routeFun.pop();
}
cancel() { //取消跳转
console.log('jhgjh')
this.routeFun.pop()
}
break() { //切换路由是执行的函数
const enterFun = this.routeFun[0];
enterFun && enterFun()
}
leave() { //切换路由
const callBacks = this.callBacks.pop();
callBacks && callBacks()
this.routeFun = [];
}
//离开保存时的特例
// **
addSaveCase() { //离开保存校验时将方法注入
setTimeout(()=>{
this.add(this.saveBeforeLeave.bind(this))
},100)
}
saveBeforeLeave() { //离开保存时触发的方法
Bus.trigger('showRouteChangeModal')
}
//** */
getCallbackNum() {
return this.routeFun.length
}
}
export default new routeHook()
\ No newline at end of file
...@@ -12,6 +12,9 @@ import Service from "@/common/js/service"; ...@@ -12,6 +12,9 @@ import Service from "@/common/js/service";
export function fetchLecturerData(params: object) { export function fetchLecturerData(params: object) {
return Service.Hades("public/courseCloud/queryTeacherVisitData", params); return Service.Hades("public/courseCloud/queryTeacherVisitData", params);
} }
export function fetchWorkWXLecturerData(params: object) {
return Service.Hades("public/courseCloud/queryWechatLiveTeacherData", params);
}
export function getQrcode(params: object) { export function getQrcode(params: object) {
return Service.Sales("public/businessShow/convertShortUrls", params); return Service.Sales("public/businessShow/convertShortUrls", params);
} }
...@@ -19,11 +22,18 @@ export function getQrcode(params: object) { ...@@ -19,11 +22,18 @@ export function getQrcode(params: object) {
export function fetchUserData(params: object) { export function fetchUserData(params: object) {
return Service.Hades("public/courseCloud/queryStudentVisitData", params); return Service.Hades("public/courseCloud/queryStudentVisitData", params);
} }
export function fetchWorkWXUserData(params: object) {
return Service.Hades("public/courseCloud/queryWechatLiveStudentData", params);
}
export function createLiveCloudCourse(params: object) { export function createLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/createLiveCloudCourse", params); return Service.Hades("public/courseCloud/createLiveCloudCourse", params);
} }
export function createWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/createWechatLiveCourse", params);
}
export function getLiveCloudCoursePage(params: object) { export function getLiveCloudCoursePage(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCoursePage", params); return Service.Hades("public/courseCloud/getLiveCloudCoursePage", params);
} }
...@@ -32,6 +42,10 @@ export function exportStudentCourseData(params: object) { ...@@ -32,6 +42,10 @@ export function exportStudentCourseData(params: object) {
return Service.Hades("public/courseCloud/exportCourseCloudVisitorAsync", params); return Service.Hades("public/courseCloud/exportCourseCloudVisitorAsync", params);
} }
export function exportWorkWXStudentCourseData(params: object) {
return Service.Hades("public/courseCloud/exportWechatLiveStudentData", params);
}
export function exportPlayBackCourseData(params: object) { export function exportPlayBackCourseData(params: object) {
return Service.Hades("public/courseCloud/exportCourseCloudPlayBackSync", params); return Service.Hades("public/courseCloud/exportCourseCloudPlayBackSync", params);
} }
...@@ -42,16 +56,27 @@ export function getLiveCloudCourseDetail(params: object) { ...@@ -42,16 +56,27 @@ export function getLiveCloudCourseDetail(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCourseDetail", params); return Service.Hades("public/courseCloud/getLiveCloudCourseDetail", params);
} }
export function getWorkWXLiveCourseDetail(params: object) {
return Service.Hades("public/courseCloud/getWechatLiveCourseDetail", params)
}
export function updateLiveCloudCourse(params: object) { export function updateLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/updateLiveCloudCourse", params); return Service.Hades("public/courseCloud/updateLiveCloudCourse", params);
} }
export function updateWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/editWechatLiveCourse", params);
}
export function turnOnOrOffLiveCloudCourse(params: object) { export function turnOnOrOffLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/turnOnOrOffLiveCloudCourse", params); return Service.Hades("public/courseCloud/turnOnOrOffLiveCloudCourse", params);
} }
export function delLiveCloudCourse(params: object) { export function delLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/delLiveCloudCourse", params); return Service.Hades("public/courseCloud/delLiveCloudCourse", params);
} }
export function delWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/delWechatLiveCourse", params);
}
//该接口主要用于培训计划关联直播课的接口(会筛选掉已关联的直播课) //该接口主要用于培训计划关联直播课的接口(会筛选掉已关联的直播课)
export function getLiveCloudCourseBasePage(params: object) { export function getLiveCloudCourseBasePage(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCourseBasePage", params); return Service.Hades("public/courseCloud/getLiveCloudCourseBasePage", params);
......
...@@ -10,7 +10,7 @@ import { ...@@ -10,7 +10,7 @@ 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 lineDetailWatchInfo, createWorkWXLiveCourse, fetchWorkWXLecturerData, fetchWorkWXUserData, getWorkWXLiveCourseDetail, updateWorkWXLiveCourse, delWorkWXLiveCourse, exportWorkWXStudentCourseData
} from '@/data-source/course/request-api'; } from '@/data-source/course/request-api';
export default class courseService { export default class courseService {
...@@ -18,6 +18,10 @@ export default class courseService { ...@@ -18,6 +18,10 @@ export default class courseService {
static fetchLecturerData(params: any) { static fetchLecturerData(params: any) {
return fetchLecturerData(params); return fetchLecturerData(params);
} }
// 获取企微讲师上课数据
static fetchWorkWXLecturerData(params: any) {
return fetchWorkWXLecturerData(params);
}
// 生成二维码 // 生成二维码
static getQrcode(params: any) { static getQrcode(params: any) {
...@@ -28,17 +32,29 @@ export default class courseService { ...@@ -28,17 +32,29 @@ export default class courseService {
static fetchUserData(params: any) { static fetchUserData(params: any) {
return fetchUserData(params); return fetchUserData(params);
} }
// 获取企微学员上课数据
static fetchWorkWXUserData(params: any) {
return fetchWorkWXUserData(params);
}
static createLiveCloudCourse(params: any) { static createLiveCloudCourse(params: any) {
return createLiveCloudCourse(params); return createLiveCloudCourse(params);
} }
//创建企微直播课
static createWorkWXLiveCourse(params: any) {
return createWorkWXLiveCourse(params)
}
static getLiveCloudCoursePage(params: any) { static getLiveCloudCoursePage(params: any) {
return getLiveCloudCoursePage(params); return getLiveCloudCoursePage({...params,terminalTypeEnum:"B_WEB"});
} }
// 导出学生上课数据 // 导出学生上课数据
static exportStudentCourseData(params: any) { static exportStudentCourseData(params: any) {
return exportStudentCourseData(params); return exportStudentCourseData(params);
} }
// 导出企微学生上课数据
static exportWorkWXStudentCourseData(params: any) {
return exportWorkWXStudentCourseData(params);
}
// 导出回放数据 // 导出回放数据
static exportPlayBackCourseData(params: any) { static exportPlayBackCourseData(params: any) {
...@@ -53,15 +69,27 @@ export default class courseService { ...@@ -53,15 +69,27 @@ export default class courseService {
static getLiveCloudCourseDetail(params: any) { static getLiveCloudCourseDetail(params: any) {
return getLiveCloudCourseDetail(params); return getLiveCloudCourseDetail(params);
} }
//获取企微直播详情
static getWorkWXLiveCourseDetail(params: any) {
return getWorkWXLiveCourseDetail(params);
}
static updateLiveCloudCourse(params: any) { static updateLiveCloudCourse(params: any) {
return updateLiveCloudCourse(params); return updateLiveCloudCourse(params);
} }
//编辑企微直播
static updateWorkWXLiveCourse(params: any) {
return updateWorkWXLiveCourse(params);
}
static turnOnOrOffLiveCloudCourse(params: any) { static turnOnOrOffLiveCloudCourse(params: any) {
return turnOnOrOffLiveCloudCourse(params); return turnOnOrOffLiveCloudCourse(params);
} }
static delLiveCloudCourse(params: any) { static delLiveCloudCourse(params: any) {
return delLiveCloudCourse(params); return delLiveCloudCourse(params);
} }
//删除企微直播
static delWorkWXLiveCourse(params: any) {
return delWorkWXLiveCourse(params);
}
static changeVideoShelfState(params: any) { static changeVideoShelfState(params: any) {
return changeVideoShelfState(params); return changeVideoShelfState(params);
} }
......
declare module 'jquery' declare module 'jquery'
declare module 'cropper' declare module 'cropper'
declare module 'ExamShareModal' declare module 'ExamShareModal'
declare module 'routeHooks'
// declare var this: any // declare var this: any
\ No newline at end of file
...@@ -24,6 +24,7 @@ import User from '@/common/js/user'; ...@@ -24,6 +24,7 @@ import User from '@/common/js/user';
import Service from "@/common/js/service"; import Service from "@/common/js/service";
import BaseService from '@/domains/basic-domain/baseService'; import BaseService from '@/domains/basic-domain/baseService';
import {brandName,BRAND,brandIcon} from '@/domains/brand/constants' import {brandName,BRAND,brandIcon} from '@/domains/brand/constants'
import routeHook from '@/core/routeHook'
declare var getParameterByName: any; declare var getParameterByName: any;
declare var window: any; declare var window: any;
...@@ -39,7 +40,16 @@ document.head.appendChild(linkzh); ...@@ -39,7 +40,16 @@ document.head.appendChild(linkzh);
window.RCHistory = _.extend({}, history, { window.RCHistory = _.extend({}, history, {
push: (obj: any) => { push: (obj: any) => {
history.push(obj) console.log(routeHook.getCallbackNum(), 'routeHook.getCallbackNum()')
if (routeHook.getCallbackNum()) {
routeHook.break();
routeHook.addJump(() => {
history.push(obj)
})
} else {
history.push(obj)
}
}, },
pushState: (obj: any) => { pushState: (obj: any) => {
history.push(obj) history.push(obj)
...@@ -47,13 +57,22 @@ window.RCHistory = _.extend({}, history, { ...@@ -47,13 +57,22 @@ window.RCHistory = _.extend({}, history, {
pushStateWithStatus: (obj: any) => { pushStateWithStatus: (obj: any) => {
history.push(obj) history.push(obj)
}, },
goBack: history.goBack, goBack: () => {
console.log(routeHook.getCallbackNum(), 'routeHook.getCallbackNum()')
history.goBack()
},
location: history.location, location: history.location,
replace: (obj: any) => { replace: (obj: any) => {
history.replace(obj) history.replace(obj)
} }
}); });
window.onhashchange = () => {
console.log(132121)
routeHook.cancel()
}
function mount() { function mount() {
ReactDOM.render( ReactDOM.render(
<RootRouter />, <RootRouter />,
...@@ -81,19 +100,19 @@ if (getParameterByName('code') && isWeiXin()) { ...@@ -81,19 +100,19 @@ if (getParameterByName('code') && isWeiXin()) {
window.currentStoreUserInfo.enterpriseId = res.result.enterpriseId; window.currentStoreUserInfo.enterpriseId = res.result.enterpriseId;
mount() mount()
}) })
} else if(getParameterByName('from') === 'customer' && getParameterByName('enterpriseId') && getParameterByName('userId')){ } else if (getParameterByName('from') === 'customer' && getParameterByName('enterpriseId') && getParameterByName('userId')) {
User.setCustomerStoreId(getParameterByName('storeId')); User.setCustomerStoreId(getParameterByName('storeId'));
getWXWorkLoginNoCheck(getParameterByName('enterpriseId'),getParameterByName('userId')); //从C端跳转过来的学院自动执行免登录 getWXWorkLoginNoCheck(getParameterByName('enterpriseId'), getParameterByName('userId')); //从C端跳转过来的学院自动执行免登录
}else{ } else {
mount() mount()
} }
function getWXWorkLoginNoCheck(enterpriseId:string,userId:string) { function getWXWorkLoginNoCheck(enterpriseId: string, userId: string) {
const params = { const params = {
appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN', appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN',
enterpriseId, enterpriseId,
userId, userId,
}; };
BaseService.getWXWorkLoginNoCheck(params).then((res:any) => { BaseService.getWXWorkLoginNoCheck(params).then((res: any) => {
User.setUserId(res.result.loginInfo.userId) User.setUserId(res.result.loginInfo.userId)
User.setToken(res.result.loginInfo.xmToken) User.setToken(res.result.loginInfo.xmToken)
User.setEnterpriseId(res.result.enterpriseId) User.setEnterpriseId(res.result.enterpriseId)
......
...@@ -21,6 +21,7 @@ import { randomString } from '@/domains/basic-domain/utils'; ...@@ -21,6 +21,7 @@ import { randomString } from '@/domains/basic-domain/utils';
import Upload from '@/core/upload'; import Upload from '@/core/upload';
import PreviewCourseModal from './modal/PreviewCourseModal'; import PreviewCourseModal from './modal/PreviewCourseModal';
import CourseService from '@/domains/course-domain/CourseService'; import CourseService from '@/domains/course-domain/CourseService';
import routeHook from '@/core/routeHook'
import moment from 'moment'; import moment from 'moment';
import User from '@/common/js/user'; import User from '@/common/js/user';
import _ from 'underscore'; import _ from 'underscore';
...@@ -110,6 +111,7 @@ class AddLive extends React.Component { ...@@ -110,6 +111,7 @@ class AddLive extends React.Component {
} }
componentDidMount() { componentDidMount() {
routeHook.addSaveCase();
const { type } = this.state; const { type } = this.state;
if (type === 'edit') { if (type === 'edit') {
this.getCourseDetail(); this.getCourseDetail();
...@@ -515,19 +517,12 @@ class AddLive extends React.Component { ...@@ -515,19 +517,12 @@ class AddLive extends React.Component {
// 比较state的addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo和默认数据是否相等 // 比较state的addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo和默认数据是否相等
const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo } = this.state; const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo } = this.state;
if (!_.isEqual(addLiveBasicInfo, defaultBasicInfo) || !_.isEqual(addLiveClassInfo, defaultClassInfo) || !_.isEqual(addLiveIntroInfo, defaultIntroInfo)) { if (!_.isEqual(addLiveBasicInfo, defaultBasicInfo) || !_.isEqual(addLiveClassInfo, defaultClassInfo) || !_.isEqual(addLiveIntroInfo, defaultIntroInfo)) {
Modal.confirm({ console.log('ghjklkjh')
title: '确定要返回吗?', window.RCHistory.push({
content: '返回后,本次编辑的内容将不被保存', pathname: `/live-course`,
okText: '确认返回',
cancelText: '留在本页',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
window.RCHistory.push({
pathname: `/live-course`,
});
},
}); });
} else { } else {
routeHook.cancel()
window.RCHistory.push({ window.RCHistory.push({
pathname: `/live-course`, pathname: `/live-course`,
}); });
......
...@@ -2,7 +2,7 @@ import User from '@/common/js/user'; ...@@ -2,7 +2,7 @@ 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 CourseService from '@/domains/course-domain/CourseService'; import CourseService from '@/domains/course-domain/CourseService';
import { Button, message, Popover, Spin } from 'antd'; import { Button, message, Popover, Spin, Tooltip } from 'antd';
import React from 'react'; import React from 'react';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import dealTimeDuration from '../utils/dealTimeDuration'; import dealTimeDuration from '../utils/dealTimeDuration';
...@@ -11,7 +11,7 @@ class DataList extends React.Component { ...@@ -11,7 +11,7 @@ class DataList extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
const courseId = getParameterByName('id'); // 课程ID const courseId = getParameterByName('id'); // 课程ID
const type = getParameterByName('type'); // 来源: 大班直播 large 互动班课 interactive const type = getParameterByName('type'); // 来源: 大班直播 large 互动班课 interactive 企微直播 qiwei
this.state = { this.state = {
type, type,
teacherData: [], // 老师上课数据 teacherData: [], // 老师上课数据
...@@ -39,32 +39,72 @@ class DataList extends React.Component { ...@@ -39,32 +39,72 @@ class DataList extends React.Component {
current, current,
size, size,
}; };
CourseService.fetchUserData(params).then((res) => { if (this.state.type === "qiwei") {
if (res.result) { CourseService.fetchWorkWXUserData(params).then((res) => {
const { records = [], current, size, total } = res.result; if (res.result) {
const { records = [], current, size, total } = res.result;
this.setState({
studentData: records,
current,
size,
total,
loading: false,
});
}
});
} else {
CourseService.fetchUserData(params).then((res) => {
if (res.result) {
const { records = [], current, size, total } = res.result;
this.setState({
studentData: records,
current,
size,
total,
loading: false,
});
}
});
}
this.setState({
studentData: records,
current,
size,
total,
loading: false,
});
}
});
}; };
// 获取老师上课数据 // 获取老师上课数据
fetchLecturerData = () => { fetchLecturerData = () => {
const { liveCourseId } = this.state; const { liveCourseId } = this.state;
CourseService.fetchLecturerData({ liveCourseId }).then((res) => { if (this.state.type === "qiwei") {
if (res.result) { CourseService.fetchWorkWXLecturerData({ liveCourseId }).then((res) => {
this.setState({ if (res.result) {
teacherData: res.result, this.setState({
}); teacherData: res.result,
} });
}); }
});
} else {
CourseService.fetchLecturerData({ liveCourseId }).then((res) => {
if (res.result) {
this.setState({
teacherData: res.result,
});
}
});
}
}; };
studentTypeEnum = (type)=> {
if (type === "STUDENT") {
return "学员"
}
if (type === "NON_STUDENT") {
return "待加入"
}
if (type === "GUEST") {
return "游客"
}
}
// 进入直播次数列表 // 进入直播次数列表
getVisiterColumns() { getVisiterColumns() {
const columns = [ const columns = [
...@@ -159,27 +199,93 @@ class DataList extends React.Component { ...@@ -159,27 +199,93 @@ class DataList extends React.Component {
}, },
]; ];
return columns; const columnsWorkWX = [
{
title: '学员姓名',
dataIndex: 'name',
},
{
title: ()=> {
return (
<div>
学员类型
<Tooltip
title={()=> {
return <div>
<div>学员-已加入当前学院的企业员工</div>
<div>待加入-未加入当前学院的企业员工</div>
<div>游客-非企业员工</div>
</div>
}}>
<i className='icon iconfont' style={{fontSize:"14px",fontWeight:"400"}}> &#xe61d;</i>
</Tooltip>
</div>
)
},
dataIndex: 'studentTypeEnum',
render: (text, record) => {
return <div>{this.studentTypeEnum(record.studentTypeEnum)}</div>;
},
},
{
title: '账号类型',
dataIndex: 'accountTypeEnum',
render: (text, record) => {
return record.accountTypeEnum === "ENTERPRISE_WECHAT" ? <span style={{color:"#5289FA"}}>企业微信</span> : <span style={{color:"#1DCC65"}}>微信</span>
},
},
{
title: '累计在线时长',
dataIndex: 'totalDuration',
sorter: (a, b) => a.totalDuration - b.totalDuration,
sortDirections: ['descend', 'ascend'],
render: (text, record) => {
//如无离开时间,就置空
return <span>{text ? dealTimeDuration(text) : '00:00:00'}</span>;
},
},
];
return this.state.type === "qiwei" ? columnsWorkWX : columns;
} }
// 学员导出5.0 // 学员导出5.0
handleExportV5 = () => { handleExportV5 = () => {
const { liveCourseId, storeId } = this.state; const { liveCourseId, storeId } = this.state;
CourseService.exportStudentCourseData({ if (this.state.type === "qiwei") {
liveCourseId: liveCourseId, CourseService.exportWorkWXStudentCourseData({
exportLiveType: 'VISITOR', liveCourseId: liveCourseId,
storeId, exportLiveType: 'VISITOR',
}).then((res) => { storeId,
const link = res.result; }).then((res) => {
this.setState({ const link = res.result;
link, this.setState({
link,
});
document.getElementById('loadExcel').click();
if (res.success) {
message.success('导出成功!');
}
});
} else {
CourseService.exportStudentCourseData({
liveCourseId: liveCourseId,
exportLiveType: 'VISITOR',
storeId,
}).then((res) => {
const link = res.result;
this.setState({
link,
});
document.getElementById('loadExcel').click();
if (res.success) {
message.success('导出成功!');
}
}); });
document.getElementById('loadExcel').click(); }
if (res.success) {
message.success('导出成功!');
}
});
}; };
handleCheckEnterTimes = () => { handleCheckEnterTimes = () => {
...@@ -239,7 +345,7 @@ class DataList extends React.Component { ...@@ -239,7 +345,7 @@ class DataList extends React.Component {
}; };
render() { render() {
const { teacherData, studentData, current, size, total, loading, link } = this.state; const { teacherData, studentData, current, size, total, loading, link, type } = this.state;
return ( return (
<Spin spinning={loading}> <Spin spinning={loading}>
<a href={link} target='_blank' download id='loadExcel' style={{ position: 'absolute', left: '-10000px' }}> <a href={link} target='_blank' download id='loadExcel' style={{ position: 'absolute', left: '-10000px' }}>
...@@ -257,18 +363,22 @@ class DataList extends React.Component { ...@@ -257,18 +363,22 @@ class DataList extends React.Component {
</div> </div>
</div> </div>
<div className='times item-block'> {
<div className={`times-num ${Number(teacherData.entryNum) > 0 ? 'can-click' : ''}`}> type !== "qiwei" &&
{Number(teacherData.entryNum) > 0 ? ( <div className='times item-block'>
<Popover content={this.showTable()} trigger='click'> <div className={`times-num ${Number(teacherData.entryNum) > 0 ? 'can-click' : ''}`}>
<span className='times-num'>{teacherData.entryNum || 0}</span> {Number(teacherData.entryNum) > 0 ? (
</Popover> <Popover content={this.showTable()} trigger='click'>
) : ( <span className='times-num'>{teacherData.entryNum || 0}</span>
<span className='times-num'>{0}</span> </Popover>
)} ) : (
<span className='times-num'>{0}</span>
)}
</div>
<div className='text'>进入直播间次数</div>
</div> </div>
<div className='text'>进入直播间次数</div> }
</div>
<div className='online-duration item-block'> <div className='online-duration item-block'>
<div className='duration'>{teacherData.totalDuration ? dealTimeDuration(teacherData.totalDuration) : '00:00:00'}</div> <div className='duration'>{teacherData.totalDuration ? dealTimeDuration(teacherData.totalDuration) : '00:00:00'}</div>
......
...@@ -21,6 +21,7 @@ class DataList extends React.Component { ...@@ -21,6 +21,7 @@ class DataList extends React.Component {
} }
render() { render() {
const type = window.getParameterByName("type")
return ( return (
<div className="page data-list"> <div className="page data-list">
<Breadcrumbs <Breadcrumbs
...@@ -35,9 +36,13 @@ class DataList extends React.Component { ...@@ -35,9 +36,13 @@ class DataList extends React.Component {
<CourseData></CourseData> <CourseData></CourseData>
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab="回放记录" key="playbackData"> {
<PlaybackData></PlaybackData> type !== "qiwei" &&
</Tabs.TabPane> <Tabs.TabPane tab="回放记录" key="playbackData">
<PlaybackData></PlaybackData>
</Tabs.TabPane>
}
</Tabs> </Tabs>
</div> </div>
......
...@@ -28,7 +28,8 @@ class AddLiveBasic extends React.Component { ...@@ -28,7 +28,8 @@ class AddLiveBasic extends React.Component {
showSelectFileModal: false, showSelectFileModal: false,
cutImageBlob: null, cutImageBlob: null,
hasImgReady: false, // 图片是否上传成功 hasImgReady: false, // 图片是否上传成功
cropperInstace: null, cropperInstace:null,
courseNameLimit: props.courseNameLimit?props.courseNameLimit:40
} }
} }
componentWillUnmount() {} componentWillUnmount() {}
...@@ -105,21 +106,29 @@ class AddLiveBasic extends React.Component { ...@@ -105,21 +106,29 @@ class AddLiveBasic extends React.Component {
<span className='label'> <span className='label'>
<span className='require'>*</span>课程名称: <span className='require'>*</span>课程名称:
</span> </span>
<div id="courseName" style={_.find(this.props.exItems,(item)=>{return item === "courseName"})?{border:"1px solid red",display:"inline-block"}:{display:"inline-block"}}>
<Input <Input
value={courseName} value={courseName}
placeholder='请输入直播名称(40字以内)' placeholder={`请输入直播名称(${this.state.courseNameLimit}字以内)`}
maxLength={40} maxLength={this.state.courseNameLimit}
style={{ width: 240 }} style={{ width: 240 }}
onChange={(e) => { onChange={(e) => {
this.props.onChange('courseName', e.target.value) this.props.onChange('courseName', e.target.value)
}} }}
/> />
</div>
</div> </div>
<div className='course-cover'> <div className='course-cover'>
<span className='label'>封面图:</span> <span className='label'>封面图:</span>
<div className='course-cover__wrap'> <div className='course-cover__wrap'>
<div className='opt-btns'>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} />
</div>
</div>
<div className='opt-btns'>
<Button <Button
onClick={() => { onClick={() => {
this.setState({ this.setState({
...@@ -133,22 +142,19 @@ class AddLiveBasic extends React.Component { ...@@ -133,22 +142,19 @@ class AddLiveBasic extends React.Component {
</span> </span>
<div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div> <div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div>
</div> </div>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} />
</div>
</div>
</div> </div>
<div className='course-catalog'> <div className='course-catalog'>
<span className='label'> <span className='label'>
<span className='require'>*</span>课程分类: <span className='require'>*</span>课程分类:
</span> </span>
<div style={_.find(this.props.exItems,(item)=>{return item === "categoryId"})?{border:"1px solid red",display:"inline-block"}:{display:"inline-block"}}>
<CourseCatalogSelect <CourseCatalogSelect
value={categoryId} value={categoryId}
onChange={(value, label) => { onChange={(value, label) => {
this.handleChangeCatalogList(value, label) this.handleChangeCatalogList(value, label)
}} }}
/> />
</div>
</div> </div>
{showSelectFileModal && ( {showSelectFileModal && (
<SelectPrepareFileModal <SelectPrepareFileModal
......
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
position: relative; position: relative;
.img-content { .img-content {
margin-top: 8px;
margin-right: 20px; margin-right: 20px;
width: 299px; width: 299px;
height: 169px; height: 169px;
...@@ -41,27 +40,26 @@ ...@@ -41,27 +40,26 @@
left: 8px; left: 8px;
} }
} }
}
.opt-btns {
.default-btn {
margin-left: 14px;
color: #2966ff;
cursor: pointer;
.opt-btns { &.disabled {
.default-btn { color: #ccc;
margin-left: 14px; cursor: not-allowed;
color: #2966ff;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
}
} }
}
.ant-upload-list { .ant-upload-list {
display: none; display: none;
} }
.tips { .tips {
margin-top: 8px; margin-top: 8px;
color: #999; color: #999;
}
} }
} }
} }
......
...@@ -75,7 +75,7 @@ class AddLiveClass extends React.Component { ...@@ -75,7 +75,7 @@ class AddLiveClass extends React.Component {
// 获取助教老师列表 // 获取助教老师列表
getAssistantList = (current = 1, selectList) => { getAssistantList = (current = 1, selectList) => {
const { assistantQuery,assistantList} = this.state; const { assistantQuery,assistantList} = this.state;
const { assistantStoreUserId } = this.props.data; const { assistantStoreUserId } = this.props.data ? this.props.data:[];
const idList = selectList ? selectList : assistantStoreUserId; const idList = selectList ? selectList : assistantStoreUserId;
const _query = { const _query = {
...assistantQuery, ...assistantQuery,
......
import React, { useEffect, useState } from "react";
import { DatePicker, TimePicker, Select, Form, message } from 'antd';
import StoreService from "@/domains/store-domain/storeService";
import "./AddLiveClassInfoWorkWX.less";
import GraphicsEditor from "./GraphicsEditor";
import moment from "moment";
import _ from "underscore";
const { Option } = Select;
const defaultTeacherQuery = {
size: 15,
current: 1,
nickName:null
}
export default function AddLiveClassInfoWorkWX(props) {
const [teacherQuery, setTeacherQuery] = useState(defaultTeacherQuery)
const [teacherList, setTeacherList] = useState([])
const [hasNext, setHasNext] = useState(false)
const [introduce, setIntroduce] = useState({content:props.introduce})
const [duration, setDuration] = useState(props.data.duration)
const [cusTime, setCusTime] = useState(false)
const [beginDate, setBeginDate] = useState(props.data.startTime===0?0:moment(props.data.startTime).startOf('day').valueOf())
const [beginTime, setBeginTime] = useState(props.data.startTime)
const [endDate, setEndDate] = useState((moment(props.data.endTime).startOf('day').valueOf()))
const [endTime, setEndTime] = useState(props.data.endTime)
const [teacherId, setTeacherId] = useState(props.data.teacherId)
const [remindTime, setRemindTime] = useState(props.data.remindTime)
// useEffect(()=> {
// setBeginTime(props.data.startTime)
// setBeginDate(props.data.startTime===0?0:moment(props.data.startTime).startOf('day').valueOf())
// if (props.data.startTime !== 0) {
// setEndTime(props.data.startTime+Number(props.data.duration)*1000)
// setEndDate(moment(props.data.startTime+Number(props.data.duration)*1000).startOf('day').valueOf())
// }
// setTeacherId(props.data.teacherId)
// setRemindTime(props.data.remindTime)
// },[props.data])
useEffect(()=> {
let intro = {content:props.introduce};
setIntroduce(intro)
},[props.introduce])
useEffect(()=> {
let query = {...defaultTeacherQuery,nickName:props.data.teacherName}
setTeacherQuery(query)
},[])
function disabledDate(current) {
// Can not select days before today and today
return current && current < moment().startOf('day');
}
//开始日期
function onBeginDateChange(date, dateString) {
if (date) {
// if (date.isBefore(moment())) {
// message.warning('开始日期不能早于当前日期')
// setBeginDate(moment().startOf('day').valueOf())
// } else {
let _begindate = date.startOf('day').valueOf();
let _begintime = moment(beginTime)
let datetime = _begindate+(_begintime.hour()*60+_begintime.minute())*60*1000
setBeginTime(datetime)
props.onChange("beginTime",datetime)
setBeginDate(_begindate)
// }
} else {
setBeginDate(0)
}
}
function onBeginDateOK(date) {
console.log(date)
}
//开始时间
function onBeginTimeChange(time, dateString) {
let begin = beginDate+(time.hour()*60+time.minute())*60*1000
if (beginDate === 0) {
begin = time.valueOf()
}
setBeginTime(begin)
props.onChange("beginTime",begin)
}
function onBeginTimeOK(time) {
// if (time.isBefore(moment())) {
// message.warning('开始时间不能早于当前时间')
// return
// }
let begin = beginDate+(time.hour()*60+time.minute())*60*1000
if (beginDate === 0) {
begin = time.valueOf()
}
setBeginTime(begin)
props.onChange("beginTime",begin)
}
//结束日期
function onEndDateChange(date, dateString) {
if (date) {
let _endDate = date.startOf('day').valueOf()
let _endtime = moment(endTime)
let datetime = _endDate+(_endtime.hour()*60+_endtime.minute())*60*1000
setEndTime(datetime)
props.onChange("endTime",datetime)
setEndDate(_endDate)
} else {
setEndDate(0)
}
}
function onEndDateOK(date) {
}
//结束时间
function onEndTimeChange(time, dateString) {
// if (time.isSameOrBefore(moment(beginTime))) {
// message.warning('结束时间不能早于开始时间')
// return
// }
let end = endDate+(time.hour()*60+time.minute())*60*1000
if (endDate === 0) {
end = time.valueOf()
}
setEndTime(end)
props.onChange("endTime",end)
}
function onEndTimeOK(time) {
// if (time.isSameOrBefore(moment(beginTime))) {
// message.warning('结束时间不能早于开始时间')
// return
// }
let end = endDate+(time.hour()*60+time.minute())*60*1000
if (endDate === 0) {
end = time.valueOf()
}
setEndTime(end)
props.onChange("endTime",end)
}
function onDurationChange(value, option) {
if (value === 0) {
setCusTime(true)
props.onChange("endTime",new Date().getTime())
return
}
let d = value*60*1000;
setDuration(d)
props.onChange("endTime",beginTime+d)
}
function onTeacherChange(value, option) {
setTeacherId(value)
props.onChange("teacherId",{teacherId:value,teacherName:option ? option.children:undefined})
}
function onRemindChange(value, option) {
setRemindTime(value)
props.onChange("remindTime",value)
}
function onChangeIntro(val) {
let intro = {...introduce}
intro.content = val
setIntroduce(intro)
props.onChange("intro",val)
}
function getTeacherList(current = 1) {
let _query = {
...teacherQuery
};
StoreService.getStoreUserBasicPage(_query).then((res) => {
const { result = {} } = res;
const { records = [], total = 0, hasNext } = result;
const list = _query.current > 1 ? teacherList.concat(records) : records;
setTeacherList(list)
setHasNext(hasNext)
});
}
useEffect(()=> {
getTeacherList()
},[teacherQuery])
// 滑动加载更多讲师列表
function handleScrollTeacherList(e) {
const container = e.target;
//判定元素是否滚动到底部
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && hasNext) {
let _teacherQuery = teacherQuery;
_teacherQuery.current = _teacherQuery.current + 1
setTeacherQuery({..._teacherQuery})
}
}
return (
<div className="AddLiveClassInfoWorkWX">
<div className="begin-time item">
<span className="label"><span className="require">*</span>开始时间:</span>
<div id="startTime" style={_.find(props.exItems,(item)=>{return item === "startTime"})?{border:"1px solid red",display:"inline-block"}:{display:"inline-block"}}>
<DatePicker
placeholder="请选择开始日期"
value={beginDate===0?undefined:moment(beginDate)}
onChange={onBeginDateChange}
onOk={onBeginDateOK}
disabledDate={disabledDate}
style={{width:"180px"}}
/>
<TimePicker
value={beginTime===0?undefined:moment(beginTime)}
onChange={onBeginTimeChange}
onOk={onBeginTimeOK}
allowClear={false}
format="HH:mm"
style={{width:"120px"}}
/>
</div>
</div>
<div className="duration-time item">
{
cusTime || props.type === "edit" ? (
<>
<span className="label"><span className="require">*</span>结束时间:</span>
<div id="endTime" style={_.find(props.exItems,(item)=>{return item === "endTime"})?{border:"1px solid red",display:"inline-block"}:{display:"inline-block"}}>
<DatePicker
placeholder="请选择结束日期"
value={endDate===0?undefined:moment(endDate)}
onChange={onEndDateChange}
onOk={onEndDateOK}
disabledDate={(current)=> {
return current && current < beginDate
}}
style={{width:"180px"}}
/>
<TimePicker
value={endTime === 0?undefined:moment(endTime)}
onChange={onEndTimeChange}
onOk={onEndTimeOK}
allowClear={false}
format="HH:mm"
style={{width:"120px"}}
/>
</div>
</>
) : (
<>
<span className="label"><span className="require">*</span>时长:</span>
<Select onChange={onDurationChange} defaultValue={60} style={{width:"140px"}}>
<Option value={30}>0.5小时</Option>
<Option value={60}>1.0小时</Option>
<Option value={120}>2.0小时</Option>
<Option value={180}>3.0小时</Option>
<Option value={0}>自定义结束时间</Option>
</Select>
</>
)
}
</div>
<div className="teacher item">
<span className="label"><span className="require">*</span>讲师:</span>
<div id="teacherId" style={_.find(props.exItems,(item)=>{return item === "teacherId"})?{border:"1px solid red",display:"inline-block"}:{display:"inline-block"}}>
<Select
value={teacherId}
onChange={onTeacherChange}
style={{width:"240px"}}
placeholder="请选择讲师"
disabled={!props.isEdit ? true: false}
filterOption={(input, option) => option}
showSearch
allowClear
onPopupScroll={handleScrollTeacherList}
onSearch={(value)=> {
let query = {...teacherQuery}
query.nickName = value
query.current = 1
setTeacherQuery(query)
}}
onClear={()=> {
setTeacherQuery({
current: 1,
nickName: null,
size: 15
})
setTeacherId(undefined)
props.onChange("teacherId",{teacherId:undefined,teacherName:undefined})
}}
onDropdownVisibleChange={(open)=> {
if (open) {
let query = {...teacherQuery,nickName:null}
setTeacherQuery(query)
}
}}
>
{
teacherList.map((item, index) => {
return (
<Select.Option value={item.id} key={item.id}>{item.nickName}</Select.Option>
);
})
}
</Select>
</div>
</div>
<div className="remind-time item">
<span className="label"><span className="require">*</span>提醒时间:</span>
<Select onChange={onRemindChange} placeholder={"15分钟前"} style={{width:"130px"}}>
<Option value={0}></Option>
<Option value={300}>5分钟前</Option>
<Option value={900}>15分钟前</Option>
<Option value={3600}>1小时前</Option>
<Option value={86400}>1天前</Option>
</Select>
</div>
<div className="introduce item">
<span className="label">直播简介:</span>
<div className="intro-edit" id="intro">
<GraphicsEditor
id='intro'
isIntro={true}
maxLimit={1000}
detail={introduce}
onChange={(val) => {
onChangeIntro(val);
}}
></GraphicsEditor>
</div>
</div>
</div>
)
}
\ No newline at end of file
.AddLiveClassInfoWorkWX {
margin-left: 16px;
.item {
margin: 24px 0;
.label {
display: inline-block;
text-align: right;
width: 100px;
.require {
color: red;
}
}
}
.introduce {
display: flex;
}
}
\ No newline at end of file
...@@ -136,7 +136,7 @@ class AddLiveIntro extends React.Component { ...@@ -136,7 +136,7 @@ class AddLiveIntro extends React.Component {
<span className='label'>观看设置:</span> <span className='label'>观看设置:</span>
<div className='content'> <div className='content'>
<Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} /> <Switch checked={whetherVisitorsJoin === 'NO' ? true : false} onChange={this.whetherVisitorsJoinChange} />
<div class='instro-text'>{whetherVisitorsJoin === 'NO' ? '已开启,学员需绑定手机号才可观看' : '已关闭,学员无需绑定手机号即可观看'}</div> <div className='instro-text'>{whetherVisitorsJoin === 'NO' ? '已开启,学员需绑定手机号才可观看' : '已关闭,学员无需绑定手机号即可观看'}</div>
</div> </div>
</div> </div>
<div className='warmup'> <div className='warmup'>
......
/*
* @Author: 吴文洁
* @Date: 2020-07-17 15:49:11
* @Last Modified by: chenshu
* @Last Modified time: 2021-04-06 16:43:23
* @Description: 大班互动-添加/编辑直播课
*/
import React, { ReactElement, useEffect, useRef, useState } from 'react';
import { withRouter } from 'react-router-dom';
import { Button, message, Modal } from 'antd';
import ShowTips from '@/components/ShowTips';
import Breadcrumbs from '@/components/Breadcrumbs';
import Bus from '@/core/tbus';
import AddLiveBasic from './AddLiveBasic';
import AddLiveClassInfoWorkWX from './AddLiveClassInfoWorkWX';
import { randomString } from '@/domains/basic-domain/utils';
import Upload from '@/core/upload';
import PreviewCourseModal from '../modal/PreviewCourseModal';
import CourseService from '@/domains/course-domain/CourseService';
import routeHook from '@/core/routeHook'
import moment from 'moment';
import User from '@/common/js/user';
import _ from 'underscore';
import $ from 'jquery';
import './CreateWorkWXCourse.less';
const defaultCover = 'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png';
const defaultBasicInfo = {
courseName: '', // 课程名称
coverUrl: defaultCover,
coverId: '',
categoryId: null,
}
const defaultClassInfo = {
teacherId: null, //讲师的Id
courseName: '', //课程名称
duration: 3600, //直播时长默认1小时
remindTime: 900, //提醒时间
// startTime: new Date().getTime() + 300000,
startTime: 0
};
function CreateWorkWXCourse() {
const [id, setId] = useState(getParameterByName('id'))
const [type,setType] = useState(getParameterByName('type'))
const [loading, setLoading] = useState(false)
const [isEdit, setIsEdit] = useState(true)
const [courseState, setCourseState] = useState('UN_START')
const [editorTextLength, setEditorTextLength] = useState(0)
const [loadintroduce, setLoadintroduce] = useState(false)
const [basicInfo, setBasicInfo] = useState(defaultBasicInfo)
const [classInfo, setClassInfo] = useState(defaultClassInfo)
const [endTime, setEndTime] = useState(0)
const [introduce, setIntroduce] = useState('')
const [getInfo, setGetInfo] = useState(false)
const [previewLiveCourseModal, setPreviewLiveCourseModal] = useState()
const [exItems, setExItems] = useState([])
const [enableSubmit, setEnableSubmit] = useState(true)
useEffect(()=> {
routeHook.addSaveCase();
if (type === 'edit') {
getCourseDetail();
}else{
setGetInfo(true)
}
Bus.bind('editorLimit', (editorTextLength) => {
setEditorTextLength(editorTextLength)
});
},[])
function getCourseDetail() {
setLoading(true)
CourseService.getWorkWXLiveCourseDetail({
liveCourseId: id,
}).then((res) => {
const {
teacherId,
teacherName,
courseName,
startTime,
duration,
courseMediaVOList,
categoryId,
categoryName,
remindTime
} = res.result;
let coverId;
let coverUrl;
let hasIntro = false;
courseMediaVOList && courseMediaVOList.map((item) => {
switch (item.contentType) {
case 'COVER':
coverId = item.mediaContent;
coverUrl = item.mediaUrl;
break;
case 'INTRO':
hasIntro = true;
getIntroduce('introduce', item.mediaUrl);
break;
default:
break;
}
return item;
});
const _basicInfo = {
courseName,
coverUrl: coverUrl || defaultCover,
coverId,
categoryId,
categoryName,
};
const _classInfo = {
teacherId,
teacherName,
duration,
startTime,
endTime: startTime+Number(duration)*1000,
remindTime,
};
// 晚于开课前30分钟
if (new Date().getTime() > startTime - 1800000) {
setIsEdit(false)
}
setLoadintroduce(!hasIntro)
setLoading(false)
setBasicInfo(_basicInfo)
setClassInfo(_classInfo)
setCourseState(courseState)
if (!hasIntro) {
setGetInfo(true)
}
});
};
//获取简介
function getIntroduce(key, url) {
$.ajax({
data: {},
type: 'GET',
url,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
success: (res) => {
setLoadintroduce(true)
setIntroduce(res)
setGetInfo(true)
},
error: () => {
message.warning('获取简介失败');
},
});
};
// 修改基本信息
function handleChangeBasicInfo(field, value) {
let binfo = {...basicInfo}
binfo[field] = value
setBasicInfo(binfo)
};
//课程信息变更回调
function onClassInfoChange(field, value) {
let classinfo = {...classInfo}
console.log(field,value)
switch (field) {
case 'intro':
setIntroduce(value)
console.log(value.length)
break;
case 'beginTime':
console.log(value)
classinfo.startTime = value
setClassInfo(classinfo)
break;
case 'endTime':
console.log(value)
setEndTime(value)
break;
case 'duration':
classinfo.duration = value
setClassInfo(classinfo)
break;
case 'teacherId':
classinfo.teacherId = value.teacherId
classInfo.teacherName = value.teacherName
setClassInfo(classinfo)
break;
case 'remindTime':
classinfo.remindTime = value
setClassInfo(classinfo)
break;
default:
console.log("NULL")
}
}
// 完成创建/编辑
function handleSubmit() {
setExItems([])
//过期判断
if (User.getExpirationTime() && moment().valueOf() > Number(User.getExpirationTime())) {
Modal.warning({
title: '服务已到期',
content: '当前企业购买的小麦企学院服务已到期,如需继续使用学院功能,请尽快续费购买',
okText: '我知道了',
});
return;
}
if (type === 'edit' && isEdit && new Date().getTime() > classInfo.startTime - 1800000) {
Modal.info({
title: '提示',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
content: '晚于开课前30分钟,部分信息不可修改',
okText: '我知道了',
onOk: () => {
getCourseDetail();
},
});
return;
}
handleValidate().then((res) => {
if (!res) return;
//上传简介
Upload.uploadTextToOSS(
introduce,
`${randomString()}.txt`,
(introduceId) => {
submitRemote({ introduceId, id });
},
() => message.warning('上传课程简介失败')
);
});
};
function submitRemote({ introduceId, id }) {
setEnableSubmit(false)
routeHook.cancel()
if (type === 'add') {
if (endTime !== 0) {
classInfo.duration = String((endTime - classInfo.startTime)/1000)
}
const params = {
...classInfo,
operatorId:User.getUserId(),
introduceId,
storeId: User.getStoreId(),
...basicInfo
};
CourseService.createWorkWXLiveCourse(params).then((res) => {
setEnableSubmit(true)
if (res.success) {
message.success('新建成功');
Bus.trigger('freshCourseList')
window.RCHistory.push({
pathname: `/live-course`,
});
}
})
.catch((err)=> {
setEnableSubmit(true)
});
} else {
if (endTime !== 0) {
classInfo.duration = String((endTime - classInfo.startTime)/1000)
}
const params = {
...classInfo,
operatorId:User.getUserId(),
introduceId,
storeId: User.getStoreId(),
...basicInfo,
liveCourseId: id
};
CourseService.updateWorkWXLiveCourse(params).then((res) => {
setEnableSubmit(true)
if (res.success) {
Bus.trigger('freshCourseList')
message.success('更新成功');
window.RCHistory.push({
pathname: `/live-course`,
});
}
})
.catch((err)=> {
setEnableSubmit(true)
});
}
};
function handleValidate() {
return new Promise((resolve) => {
let _exitem = []
if (_.isEmpty(basicInfo.courseName)) {
_exitem.push("courseName")
}
if (_.isEmpty(basicInfo.categoryId)) {
_exitem.push("categoryId")
}
if (!classInfo.startTime) {
_exitem.push("startTime")
}
if (classInfo.startTime < new Date().getTime()) {
_exitem.push("startTime")
}
if (endTime !== 0 && (endTime < classInfo.startTime)) {
_exitem.push("endTime")
}
if (_.isEmpty(classInfo.teacherId)) {
_exitem.push("teacherId")
}
if (editorTextLength > 1000) {
_exitem.push("intro")
}
setExItems(_exitem)
if (_.isEmpty(basicInfo.courseName)) {
message.warning("课程名称不能为空")
let item = document.getElementById("courseName")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (_.isEmpty(basicInfo.categoryId)) {
message.warning("课程分类未选择")
let item = document.getElementById("categoryId")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (!classInfo.startTime) {
message.warning("未设置开始时间")
let item = document.getElementById("startTime")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (classInfo.startTime < new Date().getTime()) {
message.warning("开始时间不能早于现在")
let item = document.getElementById("startTime")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (endTime !== 0 && (endTime < classInfo.startTime)) {
message.warning("结束时间不能早于开始时间")
let item = document.getElementById("endTime")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (_.isEmpty(classInfo.teacherId)) {
message.warning("未设置讲师")
let item = document.getElementById("teacherId")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
if (editorTextLength > 1000) {
message.warning("直播简介超过1000个字")
let item = document.getElementById("intro")
if (item) {
item.scrollIntoView(true)
}
resolve(false)
return
}
resolve(true)
});
};
// 显示预览课程弹窗
function handleShowPreviewModal() {
// const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, type, courseState } = this.state;
const previewLiveCourseModal = (
<PreviewCourseModal
bizType="qiwei"
courseBasicInfo={basicInfo}
courseClassInfo={{...classInfo,endTime}}
courseIntroInfo={{introduce:introduce,categoryName:basicInfo.courseName}}
type={type}
courseState={courseState}
close={() => {
setPreviewLiveCourseModal(null)
}}
/>
);
setPreviewLiveCourseModal(previewLiveCourseModal)
};
// 取消编辑并返回上一级路由
function handleGoBack() {
// 比较state的addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo和默认数据是否相等
// const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo } = this.state;
if (!_.isEqual(basicInfo, defaultBasicInfo) || !_.isEqual(classInfo, defaultClassInfo) || introduce.length > 0) {
console.log('ghjklkjh')
window.RCHistory.push({
pathname: `/live-course`,
});
} else {
routeHook.cancel()
window.RCHistory.push({
pathname: `/live-course`,
});
}
};
// const { id, type, addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, isEdit, loadintroduce } = this.state;
return (
<div className='page CreateWorkWXCourse'>
<Breadcrumbs navList={type === 'add' ? '新建直播课' : '编辑直播课'} goBack={handleGoBack} />
<div className='box'>
<div className='show-tips'>
<ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
</div>
<div className='add-live-page__form'>
<div className='basic-info__wrap'>
<div className='title'>基本信息<span style={{marginLeft:"24px",color:"#2966FF",fontSize:"14px"}}>温馨提示:在直播间可控制回放录制功能。</span></div>
<AddLiveBasic isEdit={isEdit} pageType={type} data={basicInfo} onChange={handleChangeBasicInfo} courseNameLimit={20} exItems={exItems}/>
</div>
<div className='class-info__wrap'>
<div className='title'>上课信息</div>
{/* <AddLiveClass isEdit={isEdit} pageType={type} data={{ ...addLiveClassInfo, id }} onChange={handleChangeClassInfo} /> */}
{
getInfo && <AddLiveClassInfoWorkWX type={type} data={classInfo} isEdit={isEdit} introduce={introduce} onChange={onClassInfoChange} exItems={exItems}/>
}
</div>
</div>
</div>
<div className='footer shrink-footer'>
<Button onClick={handleGoBack}>取消</Button>
<Button onClick={handleShowPreviewModal}>预览</Button>
<Button type='primary' onClick={_.debounce(() => handleSubmit(), 3000, true)} disabled={!enableSubmit}>
{enableSubmit?"保存":"正在提交"}
</Button>
</div>
{previewLiveCourseModal}
</div>
);
}
export default withRouter(CreateWorkWXCourse);
.CreateWorkWXCourse {
.box {
margin-bottom: 52px !important;
}
.add-live-page__form {
margin-top: 16px;
.title {
font-size: 16px;
color: #333;
font-weight: 500;
line-height: 22px;
margin-bottom:8px;
}
.add-live__class-info {
margin-left: 14px;
.student {
margin-bottom: 16px;
}
}
.add-live__basic-info {
.course-name {
margin-left: 14px;
}
}
.add-live__intro-info {
margin-left: 50px;
}
.class-info__wrap{
margin-top: 32px;
}
.intro-info__wrap {
margin-top: 32px;
margin-bottom:74px;
}
.add-live__intro-info {
margin-left: 0;
padding-left: 16px;
.label {
width: 100px;
text-align: right;
}
}
.basic-info__wrap, .class-info__wrap, .intro-info__wrap {
.title {
position: relative;
padding-left: 14px;
&::before {
content: "";
position: absolute;
left: 0px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 10px;
background: #2966FF;
}
}
}
}
.footer {
position: fixed;
left: 196px;
bottom: 0;
height: 58px;
width: ~'calc(100% - 218px)';
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 72px;
background: #fff;
border-top: 1px solid #E8E8E8;
z-index: 9999;
.ant-btn {
margin-left: 10px;
}
}
}
\ No newline at end of file
...@@ -24,6 +24,7 @@ const defaultQuery = { ...@@ -24,6 +24,7 @@ const defaultQuery = {
teacherId: null, teacherId: null,
courseState: null, courseState: null,
shelfState: null, shelfState: null,
thirdPartType: null
} }
const defaultTeacherQuery = { const defaultTeacherQuery = {
size: 10, size: 10,
...@@ -50,6 +51,7 @@ class LiveCourseFilter extends React.Component { ...@@ -50,6 +51,7 @@ class LiveCourseFilter extends React.Component {
current, current,
size: 10, size: 10,
} }
StoreService.getStoreUserBasicPage(_query).then((res) => { StoreService.getStoreUserBasicPage(_query).then((res) => {
const { result = {} } = res const { result = {} } = res
const { records = [], total = 0, hasNext } = result const { records = [], total = 0, hasNext } = result
...@@ -150,6 +152,7 @@ class LiveCourseFilter extends React.Component { ...@@ -150,6 +152,7 @@ class LiveCourseFilter extends React.Component {
courseState: undefined, courseState: undefined,
current: 1, current: 1,
shelfState: null, shelfState: null,
thirdPartType: null
}, },
}, },
() => { () => {
...@@ -159,7 +162,7 @@ class LiveCourseFilter extends React.Component { ...@@ -159,7 +162,7 @@ class LiveCourseFilter extends React.Component {
} }
render() { render() {
const { courseName, startTime, endTime, courseState, teacherName, teacherId, shelfState } = this.state.query const { courseName, startTime, endTime, courseState, teacherName, teacherId, shelfState, thirdPartType } = this.state.query
const { expandFilter, teacherList, teacherQuery } = this.state const { expandFilter, teacherList, teacherQuery } = this.state
const { teacherId: _teahcerId } = {} const { teacherId: _teahcerId } = {}
const isTeacher = !!_teahcerId // 判断是否是老师身份 const isTeacher = !!_teahcerId // 判断是否是老师身份
...@@ -199,7 +202,7 @@ class LiveCourseFilter extends React.Component { ...@@ -199,7 +202,7 @@ class LiveCourseFilter extends React.Component {
</div> </div>
{User.getUserRole() !== 'CloudLecturer' && ( {User.getUserRole() !== 'CloudLecturer' && (
<div className='search-condition__item'> <div className='search-condition__item'>
<span>讲师:</span> <span style={{width:"70px",display:"inline-block",textAlign:"right"}}>讲师:</span>
<Select <Select
placeholder='请选择讲师' placeholder='请选择讲师'
style={{ width: 'calc(100% - 70px)' }} style={{ width: 'calc(100% - 70px)' }}
...@@ -295,6 +298,37 @@ class LiveCourseFilter extends React.Component { ...@@ -295,6 +298,37 @@ class LiveCourseFilter extends React.Component {
</Select> </Select>
</div> </div>
)} )}
{expandFilter && (
<div className='search-condition__item'>
<span className='live-type'>直播方式:</span>
<Select
style={{ width: 'calc(100% - 70px)' }}
placeholder='请选择'
allowClear={true}
onClear={(value) => {
this.setState(
{
query: {...this.state.query,thirdPartType:null}
},
() => {
this.props.onChange(this.state.query)
}
)
}}
value={thirdPartType}
onChange={(value) => {
this.handleChangeQuery('thirdPartType', value)
}}
suffixIcon={
<span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
}>
<Option value='WECHAT'>企微直播</Option>
<Option value='TENCENT'>小麦直播</Option>
</Select>
</div>
)}
</div> </div>
<div className='reset-fold-area'> <div className='reset-fold-area'>
......
...@@ -6,23 +6,26 @@ ...@@ -6,23 +6,26 @@
* @Description: 大班直播、互动班课的直播课列表 * @Description: 大班直播、互动班课的直播课列表
*/ */
import User from '@/common/js/user' import User from '@/common/js/user';
import college from '@/common/lottie/college' import WechatApi from '@/common/js/wechatApi';
import { PageControl, XMTable } from '@/components' import college from '@/common/lottie/college';
import DownloadLiveModal from '@/components/DownloadLiveModal' import { PageControl, XMTable } from '@/components';
import BaseService from '@/domains/basic-domain/baseService' import DownloadLiveModal from '@/components/DownloadLiveModal';
import { LIVE_SHARE } from '@/domains/course-domain/constants' import { isWorkWx } from '@/core/platform';
import CourseService from '@/domains/course-domain/CourseService' import BaseService from '@/domains/basic-domain/baseService';
import { QuestionCircleOutlined } from '@ant-design/icons' import { LIVE_SHARE } from '@/domains/course-domain/constants';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd' import CourseService from '@/domains/course-domain/CourseService';
import React from 'react' import { QuestionCircleOutlined } from '@ant-design/icons';
import { Route, withRouter } from 'react-router-dom' import { Dropdown, message, Badge, Modal, Switch, Tooltip, Menu } from 'antd';
import _ from 'underscore' import React from 'react';
import DataList from '../DataList/DataList' import { Route, withRouter } from 'react-router-dom';
import ManageCoursewareModal from '../modal/ManageCoursewareModal' import _ from 'underscore';
import RelatedPlanModal from '../modal/RelatedPlanModal' import DataList from '../DataList/DataList';
import ShareLiveModal from '../modal/ShareLiveModal' import ManageCoursewareModal from '../modal/ManageCoursewareModal';
import './LiveCourseList.less' import RelatedPlanModal from '../modal/RelatedPlanModal';
import ShareLiveModal from '../modal/ShareLiveModal';
import Bus from '@/core/bus';
import './LiveCourseList.less';
const { confirm } = Modal const { confirm } = Modal
const courseStateShow = { const courseStateShow = {
...@@ -63,6 +66,9 @@ class LiveCourseList extends React.Component { ...@@ -63,6 +66,9 @@ class LiveCourseList extends React.Component {
} }
componentDidMount() { componentDidMount() {
this.getDownloadVersion() this.getDownloadVersion()
Bus.bind('freshCourseList',()=>{
this.refreshCourseList()
})
} }
// 显示分享弹窗 // 显示分享弹窗
handleShowShareModal = (item, needStr = false) => { handleShowShareModal = (item, needStr = false) => {
...@@ -112,12 +118,12 @@ class LiveCourseList extends React.Component { ...@@ -112,12 +118,12 @@ class LiveCourseList extends React.Component {
// 前往上课数据页面 // 前往上课数据页面
handleLinkToClassData = (item) => { handleLinkToClassData = (item) => {
const { match } = this.props const { match } = this.props;
let type = item.thirdPartType === "WECHAT" ? "qiwei" : "large"
window.RCHistory.push({ window.RCHistory.push({
pathname: `${match.url}/live-course-data?type=large&id=${item.liveCourseId}`, pathname: `${match.url}/live-course-data?type=${type}&id=${item.liveCourseId}`,
}) });
} };
parseColumns = () => { parseColumns = () => {
let columns let columns
const userRole = User.getUserRole() const userRole = User.getUserRole()
...@@ -159,11 +165,6 @@ class LiveCourseList extends React.Component { ...@@ -159,11 +165,6 @@ class LiveCourseList extends React.Component {
<span className='course-time'> <span className='course-time'>
{window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))} {window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))}
</span> </span>
<span
className='course-status'
style={{ color: courseStateShow[record.courseState].color, border: `1px solid ${courseStateShow[record.courseState].color}` }}>
{courseStateShow[record.courseState].title}
</span>
</div> </div>
<div className='teacher-assistant'> <div className='teacher-assistant'>
<Choose> <Choose>
...@@ -215,6 +216,28 @@ class LiveCourseList extends React.Component { ...@@ -215,6 +216,28 @@ class LiveCourseList extends React.Component {
}, },
}, },
{ {
title: '上课状态',
width: '10%',
key: 'couseCatalog',
dataIndex: 'couseCatalog',
render: (val, item) => {
return <Badge
color={courseStateShow[item.courseState].color}
size="default"
text={<span style={{color:"#666666"}}>{courseStateShow[item.courseState].title}</span>}
/>;
},
},
{
title: '直播方式',
width: '10%',
key: 'couseCatalog',
dataIndex: 'couseCatalog',
render: (val, item) => {
return <div>{item.thirdPartType === "WECHAT" ? "企微直播":"小麦直播"}</div>;
},
},
{
title: '课程分类', title: '课程分类',
width: '10%', width: '10%',
key: 'couseCatalog', key: 'couseCatalog',
...@@ -316,7 +339,7 @@ class LiveCourseList extends React.Component { ...@@ -316,7 +339,7 @@ class LiveCourseList 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={index}>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}{' '} {item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}{' '}
</span> </span>
) )
...@@ -447,11 +470,6 @@ class LiveCourseList extends React.Component { ...@@ -447,11 +470,6 @@ class LiveCourseList extends React.Component {
<span className='course-time'> <span className='course-time'>
{window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))} {window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))}
</span> </span>
<span
className='course-status'
style={{ color: courseStateShow[record.courseState].color, border: `1px solid ${courseStateShow[record.courseState].color}` }}>
{courseStateShow[record.courseState].title}
</span>
</div> </div>
<div className='teacher-assistant'> <div className='teacher-assistant'>
<Choose> <Choose>
...@@ -615,24 +633,81 @@ class LiveCourseList extends React.Component { ...@@ -615,24 +633,81 @@ class LiveCourseList extends React.Component {
} }
renderMoreOperate = (item) => { renderMoreOperate = (item) => {
let now = new Date().getTime()
return ( return (
<div className='live-course-more-menu'> <Menu
{(User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager') && ( onClick={({key})=> {
<div className='operate__item' onClick={() => this.handleRelatedModalShow(item)}> if (key === "link") {
this.handleRelatedModalShow(item)
} else if (key === "edit") {
this.toEditCoursePage(item)
} else if (key === "del") {
this.handleDelete(item)
}
}}
>
{
item.thirdPartType === "WECHAT" &&
<Tooltip placement="left" title="企微直播,暂不支持关联培训任务">
<Menu.Item style={{color:"#999999"}}>
关联培训计划
</Menu.Item>
</Tooltip>
}
{
item.thirdPartType !== "WECHAT" &&
<Menu.Item disabled={!(User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager')} key="link">
关联培训计划 关联培训计划
</div> </Menu.Item>
)} }
<div className='operate__item' onClick={() => this.toEditCoursePage(item)}> {
编辑 (item.courseState === "STARTING" || item.courseState === "FINISH") &&
</div> <Tooltip placement="left" title={`${item.courseState === "STARTING"?"直播已开始,不能编辑":"直播已结束,不能编辑"}`}>
{item.courseState !== 'STARTING' && ( <Menu.Item style={{color:"#999999"}}>
<div className='operate__item' onClick={() => this.handleDelete(item)}> 编辑
</Menu.Item>
</Tooltip>
}
{
item.courseState !== "STARTING" && item.courseState !== "FINISH" &&
<Menu.Item key="edit">
编辑
</Menu.Item>
}
{
(item.courseState === "STARTING" || ((now > item.startTime && now < item.endTime) && item.courseState !== "FINISH")) &&
<Tooltip placement="left" title="直播进行中,不能删除">
<Menu.Item style={{color:"#999999"}}>
删除 删除
</div> </Menu.Item>
)} </Tooltip>
</div> }
{
(item.courseState !== "STARTING" && ((now < item.startTime || now > item.endTime) || item.courseState === "FINISH")) &&
<Menu.Item key="del">
删除
</Menu.Item>
}
</Menu>
) )
} // return (
// <div className='live-course-more-menu'>
// {(User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager') && (
// <div className='operate__item' onClick={() => this.handleRelatedModalShow(item)}>
// 关联培训计划
// </div>
// )}
// <div className='operate__item' onClick={() => this.toEditCoursePage(item)}>
// 编辑
// </div>
// {item.courseState !== 'STARTING' && (
// <div className='operate__item' onClick={() => this.handleDelete(item)}>
// 删除
// </div>
// )}
// </div>
// );
};
handleDelete = (record) => { handleDelete = (record) => {
return confirm({ return confirm({
title: '你确定要删除直播课?', title: '你确定要删除直播课?',
...@@ -651,24 +726,61 @@ class LiveCourseList extends React.Component { ...@@ -651,24 +726,61 @@ class LiveCourseList extends React.Component {
deleteConfirm = (item) => { deleteConfirm = (item) => {
const params = { const params = {
liveCourseId: item.liveCourseId, liveCourseId: item.liveCourseId,
};
if (item.thirdPartType === "WECHAT") {
CourseService.delWorkWXLiveCourse(params).then((res) => {
if (res.success) {
message.success('已删除');
this.props.onChange();
}
});
} else {
CourseService.delLiveCloudCourse(params).then((res) => {
if (res.success) {
message.success('已删除');
this.props.onChange();
}
});
} }
CourseService.delLiveCloudCourse(params).then((res) => {
if (res.success) { };
message.success('已删除')
this.props.onChange()
}
})
}
toEditCoursePage = (item) => { toEditCoursePage = (item) => {
window.RCHistory.push({ if (item.thirdPartType === "WECHAT") {
pathname: `/create-live-course?type=edit&id=${item.liveCourseId}`, window.RCHistory.push({
}) pathname: `/live-course/createqwcourse?type=edit&id=${item.liveCourseId}`,
} });
} else {
window.RCHistory.push({
pathname: `/create-live-course?type=edit&id=${item.liveCourseId}`,
});
}
};
refreshCourseList = () => { refreshCourseList = () => {
this.props.onChange(this.props.query) this.props.onChange(this.props.query)
} }
//进入直播间 //进入直播间
handleEnterLiveRoom = (item) => { handleEnterLiveRoom = (item) => {
if (item.thirdPartType === "WECHAT") {
//进入企微直播间
if (!isWorkWx()) {
Modal.warning({
title: '提示',
content: "请使用企业微信进入直播间"
})
return
}
WechatApi.enterLiveRoom(item.livingId).then((res)=> {
console.log(res)
}).catch((err)=> {
Modal.warning({
title:"提示",
content: err
})
})
return
}
if (item.startTime - Date.now() > 1800000) { if (item.startTime - Date.now() > 1800000) {
Modal.warning({ Modal.warning({
title: '你来得太早了', title: '你来得太早了',
...@@ -723,7 +835,34 @@ class LiveCourseList extends React.Component { ...@@ -723,7 +835,34 @@ class LiveCourseList extends React.Component {
}) })
} }
handleViewPlayBack = (item) => { handleViewPlayBack = (item) => {
let htmlUrl if (item.thirdPartType === "WECHAT") {
if (!isWorkWx()) {
Modal.warning({
title:"提示",
content:"请使用企业微信进入回放"
})
return
}
if (item.startTime + 15*60*1000 < new Date().getTime()) {
Modal.warning({
title: '提示',
content: "该直播课的回放视频已失效",
});
return
}
WechatApi.replayLiving(item.livingId)
.then((res)=> {
console.log("进入企微回放")
})
.catch((err)=> {
Modal.warning({
title: '提示',
content: err,
});
})
return
}
let htmlUrl;
if (item.teacherId === User.getUserId()) { if (item.teacherId === User.getUserId()) {
htmlUrl = `${LIVE_SHARE}replay/${item.liveCourseId}?teacherId=${User.getUserId()}&id=${User.getStoreId()}` htmlUrl = `${LIVE_SHARE}replay/${item.liveCourseId}?teacherId=${User.getUserId()}&id=${User.getStoreId()}`
} else if (_.pluck(item.admins, 'adminId').includes(User.getUserId())) { } else if (_.pluck(item.admins, 'adminId').includes(User.getUserId())) {
......
...@@ -9,22 +9,57 @@ ...@@ -9,22 +9,57 @@
import React from 'react'; import React from 'react';
import { Button, Modal, message } from 'antd'; import { Button, Modal, message } from 'antd';
import Service from '@/common/js/service'; import Service from '@/common/js/service';
import { withRouter ,Route} from "react-router-dom";
import './liveCourseOpt.less'; import './liveCourseOpt.less';
import BaseService from "@/domains/basic-domain/baseService"; import BaseService from "@/domains/basic-domain/baseService";
import CreateWorkWXCourse from './CreateWorkWXCourse'
import User from '@/common/js/user' import User from '@/common/js/user'
import LiveModeSelect from './LiveModeSelect';
class LiveCourseOpt extends React.Component { class LiveCourseOpt extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isMac: /macintosh|mac os x/i.test(navigator.userAgent), isMac: /macintosh|mac os x/i.test(navigator.userAgent),
showModeSelect: false,
} }
} }
handleCreateLiveCouese = ()=>{ handleCreateLiveCouese = ()=>{
window.RCHistory.push({ this.setState({
pathname: '/create-live-course?type=add', showModeSelect: true
})
// window.RCHistory.push({
// pathname: '/create-live-course?type=add',
// })
}
onModeSelectClose = ()=> {
this.setState({
showModeSelect: false
})
}
onModeSelected = (type)=> {
this.setState({
showModeSelect: false
}) })
if (type === 0) {
window.RCHistory.push({
pathname: '/create-live-course?type=add',
})
} else if (type === 1) {
const { match } = this.props;
this.props.history.push(`${match.url}/createqwcourse?type=add`)
}
}
handleCreateQWCouese=()=>{
const { match } = this.props;
this.props.history.push(`${match.url}/createqwcourse`)
} }
// 下载直播客户端 // 下载直播客户端
handleDownloadClient = () => { handleDownloadClient = () => {
const { isMac } = this.state; const { isMac } = this.state;
...@@ -47,17 +82,21 @@ class LiveCourseOpt extends React.Component { ...@@ -47,17 +82,21 @@ class LiveCourseOpt extends React.Component {
} }
render() { render() {
const userRole = User.getUserRole(); const userRole = User.getUserRole();
const { match } = this.props;
return ( return (
<div className="live-course-opt"> <div className="live-course-opt">
<LiveModeSelect onClose={this.onModeSelectClose} onSelected={this.onModeSelected} isShow={this.state.showModeSelect}/>
<div className="opt__left"> <div className="opt__left">
{ userRole !== "CloudLecturer" && { userRole !== "CloudLecturer" &&
<Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button> <Button type="primary" onClick={this.handleCreateLiveCouese}>新建直播课</Button>
} }
<Button onClick={this.handleDownloadClient}>下载直播客户端</Button> {/* <Button type="primary" onClick={this.handleCreateQWCouese}>新建企微直播课</Button> */}
{!this.state.isMac && <Button onClick={this.handleDownloadClient}>下载直播客户端</Button>}
</div> </div>
<Route path={`${match.url}/createqwcourse`} component={CreateWorkWXCourse} />
</div> </div>
) )
} }
} }
export default LiveCourseOpt; export default withRouter(LiveCourseOpt);
\ No newline at end of file \ No newline at end of file
.livemode-select {
position: fixed;
display: flex;
justify-content: center;
align-items: center;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0,0,0,0.4);
z-index: 1000;
.dialog {
width: 680px;
height: 438px;
background: #FFFFFF;
border-radius: 6px;
.header {
display: flex;
justify-content: space-between;
align-items: center;
width: 680px;
height: 50px;
border-bottom: 1px solid #E8E8E8;
.title {
font-size: 16px;
color: #333333;
font-weight: 400;
margin-left: 23px;
}
.close {
color: #999999;
margin-right: 23px;
font-size: 12px;
cursor: pointer;
}
}
.content {
display: flex;
justify-content: space-between;
margin: 43px 95px 50px 95px;
.item {
display: inline-block;
width: 221px;
height: 294px;
background: #FFFFFF;
box-shadow: 0px 2px 8px 3px rgba(41, 102, 255, 0.1);
border-radius: 5px;
text-align: center;
background-size: contain;
background-repeat: no-repeat;
.logo {
width: 80px;
height: 80px;
margin: 31px auto 0 auto;
}
.item-title {
font-size: 16px;
font-weight: 500;
color: #333333;
margin: 25px auto 0 auto;
}
.des {
margin: 14px auto 0 auto;
font-size: 14px;
font-weight: 400;
color: #666666;
}
.button {
font-size: 14px;
font-weight: 400;
color: white;
width: 100px;
height: 32px;
background: #2966FF;
border-radius: 16px;
margin: 25px auto 0 auto;
padding-top: 5px;
cursor: pointer;
}
}
.xiaomai-logo {
background-image: url("https://image.xiaomaiketang.com/xm/rjwN8Yc7xa.png");
}
.qiwei-logo {
background-image: url("https://image.xiaomaiketang.com/xm/CzdyntSxha.png");
}
}
}
}
.livemode-select-none {
display: none;
}
\ No newline at end of file
import React, { useState } from "react";
import "./LiveModeSelect.less"
import { createPortal } from "react-dom";
interface LiveModeSelectProps {
isShow: boolean;
onClose: ()=> void;
onSelected: (type: number)=> void;
}
export default function LiveModeSelect(props: LiveModeSelectProps) {
const handleSelect0 = (e: React.MouseEvent<HTMLDivElement>)=> {
const { onSelected } = props
onSelected(0)
}
const handleSelect1 = (e: React.MouseEvent<HTMLDivElement>)=> {
const { onSelected } = props
onSelected(1)
}
const handleClose = (e: React.MouseEvent<HTMLDivElement>)=> {
props.onClose()
}
return createPortal(
<div className={`livemode-select${props.isShow ? "":" livemode-select-none"}`}>
<div className="dialog">
<div className="header">
<div className="title">选择直播方式</div>
<span className="icon iconfont close" onClick={handleClose}>&#xe6ef;</span>
</div>
<div className="content">
<div className="item xiaomai-logo">
<div className="logo"></div>
<div className="item-title">小麦直播</div>
<div className="des">通过小麦企学院“PC客户<br/>端”进行直播</div>
<div className="button" onClick={handleSelect0}>立即创建</div>
</div>
<div className="item qiwei-logo">
<div className="logo qiwei-logo"></div>
<div className="item-title">企微直播</div>
<div className="des">通过“企业微信APP”<br/>进行直播</div>
<div className="button" onClick={handleSelect1}>立即创建</div>
</div>
</div>
</div>
</div>,
document.body
)
}
\ No newline at end of file
...@@ -333,6 +333,7 @@ class ManageCoursewareModal extends React.Component { ...@@ -333,6 +333,7 @@ class ManageCoursewareModal extends React.Component {
]; ];
const { list, scanFileModal, editData, cancelObject, showSelectFileModal, selectedFileList, diskList, showPreviewModal, previewStatus, url } = this.state; const { list, scanFileModal, editData, cancelObject, showSelectFileModal, selectedFileList, diskList, showPreviewModal, previewStatus, url } = this.state;
const _list = _.reject(list, (item) => cancelObject[item.id]); const _list = _.reject(list, (item) => cancelObject[item.id]);
const { thirdPartType } = this.props.data
return ( return (
<Modal <Modal
visible={true} visible={true}
...@@ -348,10 +349,17 @@ class ManageCoursewareModal extends React.Component { ...@@ -348,10 +349,17 @@ class ManageCoursewareModal extends React.Component {
{_.isEmpty(_list) ? ( {_.isEmpty(_list) ? (
<div className='empty-body'> <div className='empty-body'>
<div id='lottie-box' className='empty-image'></div> <div id='lottie-box' className='empty-image'></div>
<Button className='empty-button' type='primary' onClick={() => this.addFile()}> { thirdPartType === "WECHAT" && <div className="qiwei-tip">企微直播<br/>Mac暂不支持上传课件,Windows可在直播间添加课件</div>}
<Button className='empty-button' type='primary'
disabled={thirdPartType === "WECHAT"}
onClick={() => {
if (thirdPartType !== "WECHAT") {
this.addFile()
}
}}>
上传课件 上传课件
</Button> </Button>
<p className='empty-tip'>提前上传直播需要的课件和素材,直播将会变得更便捷!</p> { thirdPartType !== "WECHAT" && <p className='empty-tip'>提前上传直播需要的课件和素材,直播将会变得更便捷!</p>}
</div> </div>
) : ( ) : (
<div className='manage-body'> <div className='manage-body'>
......
...@@ -11,6 +11,14 @@ ...@@ -11,6 +11,14 @@
width:150px; width:150px;
height:150px; height:150px;
} }
.qiwei-tip {
font-size: 14px;
font-weight: 400;
color: #999;
text-align: center;
margin-top: 12px;
margin-bottom: 12px;
}
.empty-button { .empty-button {
display: block; display: block;
margin: 0 auto 8px; margin: 0 auto 8px;
......
...@@ -107,47 +107,54 @@ class PreviewCourseModal extends React.Component { ...@@ -107,47 +107,54 @@ class PreviewCourseModal extends React.Component {
timeHorizonStart, timeHorizonStart,
timeHorizonEnd, timeHorizonEnd,
teacherName, teacherName,
duration
} = courseClassInfo; } = courseClassInfo;
const { introduce, categoryName } = courseIntroInfo; const { introduce, categoryName } = courseIntroInfo;
let { activeTab } = this.state; let { activeTab } = this.state;
let liveDateStr, startTimeStr, endTimeStr; let liveDateStr, startTimeStr, endTimeStr;
if (type === "add") { if (this.props.bizType === "qiwei") {
const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD"); startTimeStr = moment(startTime === 0?moment().valueOf():startTime).format("YYYY-MM-DD HH:mm")
console.log("_liveDate", _liveDate); endTimeStr = moment(endTime === 0?moment(startTime+Number(duration)*1000).valueOf():endTime).format("HH:mm")
const _timeHorizonStart = moment(startTime).format("HH:mm");
const _timeHorizonEnd = moment(endTime).format("HH:mm");
const _startTime = moment(_liveDate + " " + _timeHorizonStart).format(
"x"
);
const _endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x");
const {
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr,
endTimeStr: _endTimeStr,
} = this.dealWithTime(_startTime, _endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
} else { } else {
const _liveDate = moment(liveDate).format("YYYY-MM-DD"); if (type === "add") {
const _timeHorizonStart = moment(timeHorizonStart).format("HH:mm"); const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD");
const _timeHorizonEnd = moment(timeHorizonEnd).format("HH:mm"); console.log("_liveDate", _liveDate);
const startTime = moment(_liveDate + " " + _timeHorizonStart).format("x"); const _timeHorizonStart = moment(startTime).format("HH:mm");
const endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x"); const _timeHorizonEnd = moment(endTime).format("HH:mm");
const { const _startTime = moment(_liveDate + " " + _timeHorizonStart).format(
liveDateStr: _liveDateStr, "x"
startTimeStr: _startTimeStr, );
endTimeStr: _endTimeStr, const _endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x");
} = this.dealWithTime(startTime, endTime); const {
liveDateStr: _liveDateStr,
liveDateStr = _liveDateStr; startTimeStr: _startTimeStr,
startTimeStr = _startTimeStr; endTimeStr: _endTimeStr,
endTimeStr = _endTimeStr; } = this.dealWithTime(_startTime, _endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
} else {
const _liveDate = moment(liveDate).format("YYYY-MM-DD");
const _timeHorizonStart = moment(timeHorizonStart).format("HH:mm");
const _timeHorizonEnd = moment(timeHorizonEnd).format("HH:mm");
const startTime = moment(_liveDate + " " + _timeHorizonStart).format("x");
const endTime = moment(_liveDate + " " + _timeHorizonEnd).format("x");
const {
liveDateStr: _liveDateStr,
startTimeStr: _startTimeStr,
endTimeStr: _endTimeStr,
} = this.dealWithTime(startTime, endTime);
liveDateStr = _liveDateStr;
startTimeStr = _startTimeStr;
endTimeStr = _endTimeStr;
}
} }
return ( return (
<Modal <Modal
title="预览" title="预览"
......
...@@ -102,7 +102,7 @@ class ShareLiveModal extends React.Component { ...@@ -102,7 +102,7 @@ class ShareLiveModal extends React.Component {
render() { render() {
const { courseDivision, data, type, title } = this.props; const { courseDivision, data, type, title } = this.props;
const { courseName, scheduleVideoUrl, courseMediaVOS, coverUrl } = data; const { courseName, scheduleVideoUrl, courseMediaVOS, coverUrl, thirdPartType } = data;
const { shareUrl, showImg, time } = this.state; const { shareUrl, showImg, time } = this.state;
// 判断是否是默认图, 默认图不需要在URL后面增加字符串 // 判断是否是默认图, 默认图不需要在URL后面增加字符串
let coverImgSrc = ''; let coverImgSrc = '';
...@@ -188,8 +188,8 @@ class ShareLiveModal extends React.Component { ...@@ -188,8 +188,8 @@ class ShareLiveModal extends React.Component {
<div className='right'> <div className='right'>
<div className='share-poster right__item'> <div className='share-poster right__item'>
<div className='title'>① 海报分享</div> <div className='title'>① 海报分享</div>
{type === 'liveClass' && <div className='sub-title'>学员可通过微信扫描海报二维码,观看{title}</div>} {type === 'liveClass' && <div className='sub-title'>学员可通过微信{thirdPartType === "WECHAT"?"/企业微信":""}扫描海报二维码,观看{title}</div>}
{type === 'videoClass' && <div className='sub-title'>学员可通过微信识别二维码,报名观看{title}</div>} {type === 'videoClass' && <div className='sub-title'>学员可通过微信{thirdPartType === "WECHAT"?"/企业微信":""}识别二维码,报名观看{title}</div>}
<div className='content' onClick={_.debounce(this.handleDownloadPoster, 1000, true)}> <div className='content' onClick={_.debounce(this.handleDownloadPoster, 1000, true)}>
下载海报 下载海报
...@@ -198,7 +198,7 @@ class ShareLiveModal extends React.Component { ...@@ -198,7 +198,7 @@ class ShareLiveModal extends React.Component {
<div className='share-url right__item'> <div className='share-url right__item'>
<div className='title'>② 链接分享</div> <div className='title'>② 链接分享</div>
{type === 'liveClass' && <div className='sub-title'>学员可通过微信打开以下链接,观看{title}</div>} {type === 'liveClass' && <div className='sub-title'>学员可通过微信{thirdPartType === "WECHAT"?"/企业微信":""}打开以下链接,观看{title}</div>}
{type === 'videoClass' && <div className='sub-title'>学员可通过打开链接,报名观看{title}</div>} {type === 'videoClass' && <div className='sub-title'>学员可通过打开链接,报名观看{title}</div>}
<div className='content url-content'> <div className='content url-content'>
<div className='share-url' id='shareUrl'> <div className='share-url' id='shareUrl'>
......
...@@ -309,7 +309,6 @@ class SelectOperatorModal extends React.Component { ...@@ -309,7 +309,6 @@ class SelectOperatorModal extends React.Component {
), ),
key: 'course', key: 'course',
dataIndex: 'course', dataIndex: 'course',
width: '40%',
render: (val, record) => { render: (val, record) => {
let hasCover = false; let hasCover = false;
return ( return (
...@@ -341,7 +340,7 @@ class SelectOperatorModal extends React.Component { ...@@ -341,7 +340,7 @@ class SelectOperatorModal extends React.Component {
title: '上课时间', title: '上课时间',
key: 'courseTime', key: 'courseTime',
dataIndex: 'courseTime', dataIndex: 'courseTime',
width: '40%', width: 150,
render: (val, record) => { render: (val, record) => {
return ( return (
<div> <div>
...@@ -357,7 +356,7 @@ class SelectOperatorModal extends React.Component { ...@@ -357,7 +356,7 @@ class SelectOperatorModal extends React.Component {
title: '学院展示', title: '学院展示',
key: 'shelfState', key: 'shelfState',
dataIndex: 'shelfState', dataIndex: 'shelfState',
width: '20%', width: 120,
render: (val, record) => { render: (val, record) => {
return ( return (
<span> <span>
......
...@@ -16,11 +16,10 @@ import User from '@/common/js/user'; ...@@ -16,11 +16,10 @@ import User from '@/common/js/user';
import BaseService from "@/domains/basic-domain/baseService"; import BaseService from "@/domains/basic-domain/baseService";
import moment from 'moment'; import moment from 'moment';
import { VersionContext, VersionInfo, XMContext } from '@/store/context'; import { VersionContext, VersionInfo, XMContext } from '@/store/context';
import WechatApi from '@/common/js/wechatApi';
import { setStoreGroupPermission, setStorePermission, setStoreGroupList, setStoreList, setWechatLogin } from '@/store/actions/index'; import { setStoreGroupPermission, setStorePermission, setStoreGroupList, setStoreList, setWechatLogin } from '@/store/actions/index';
import Service from "@/common/js/service"; import Service from "@/common/js/service";
import Bus from '@/core/tbus'; import Bus from '@/core/tbus';
import WechatApi from '@/common/js/wechatApi';
import { func } from 'prop-types';
const { Footer, Sider, Content } = Layout; const { Footer, Sider, Content } = Layout;
......
import React , { useContext, useEffect ,useState}from 'react' import React, { useContext, useEffect, useState } from 'react'
import './Main.less'; import './Main.less';
import { MainRoutes, RedirectRoutes } from '@/routes'; import { Modal } from 'antd';
import { MainRoutes, RedirectRoutes } from '@/routes';
import routeHook from '@/core/routeHook'
import Bus from '@/core//bus';
function Main(props) {
const { menuType } = props;
console.log("menuType", menuType);
useEffect(() => {
Bus.bind('showRouteChangeModal', () => {
Modal.confirm({
title: '确定要返回吗?',
content: '返回后,本次编辑的内容将不被保存',
okText: '确认返回',
cancelText: '留在本页',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
routeHook.leave()
},
});
})
}, [])
function Main(props){
const {menuType} = props;
console.log("menuType",menuType);
return ( return (
<div <div
className={menuType ? `right-container has-nav` : `right-container has-nav right-container-vertical`} className={menuType ? `right-container has-nav` : `right-container has-nav right-container-vertical`}
id="rightContainer" id="rightContainer"
> >
<MainRoutes/> <MainRoutes />
<RedirectRoutes/> <RedirectRoutes />
</div> </div>
) )
} }
......
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect } from 'react';
import qrcode from '@/libs/qrcode/qrcode.js'; 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 qrcode from "@/libs/qrcode/qrcode.js";
import { PATH } from '@/domains/basic-domain/constants'; import { PATH } from '@/domains/basic-domain/constants';
import { corpType } from '@/domains/brand/constants' import { corpType } from '@/domains/brand/constants'
import './WechatLogin.less'; import './WechatLogin.less';
...@@ -9,6 +9,7 @@ import { brandName, BRAND, brandIcon, brandLogo } from '@/domains/brand/constant ...@@ -9,6 +9,7 @@ import { brandName, BRAND, brandIcon, brandLogo } from '@/domains/brand/constant
declare var location: any; declare var location: any;
declare var window: any; declare var window: any;
export default function WechatLogin(props: any) { export default function WechatLogin(props: any) {
const freshTime = 60; const freshTime = 60;
const init: any = null; const init: any = null;
......
...@@ -18,22 +18,6 @@ import _ from 'underscore'; ...@@ -18,22 +18,6 @@ import _ from 'underscore';
import SwitchRoute from '@/modules/root/SwitchRoute'; import SwitchRoute from '@/modules/root/SwitchRoute';
import ErrorCollege from '@/modules/root/ErrorCollege'; import ErrorCollege from '@/modules/root/ErrorCollege';
const history = createHashHistory(); const history = createHashHistory();
window.RCHistory = _.extend({}, history, {
push: (obj: any) => {
history.push(obj);
},
pushState: (obj: any) => {
history.push(obj);
},
pushStateWithStatus: (obj: any) => {
history.push(obj);
},
goBack: history.goBack,
location: history.location,
replace: (obj: any) => {
history.replace(obj);
},
});
export const RootRouter = () => { export const RootRouter = () => {
return ( return (
......
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