Commit 1df318b5 by zhangleyuan

feat:解决合并代码后的冲突

parents b24bd04f 9e9c18a5
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -96,6 +96,12 @@ class Axios {
content: `当前企业购买的${window.brandName}服务已到期,如需继续使用学院功能,请尽快续费购买`,
okText: "我知道了"
})
} else if (resultCode === "LIVE_START_FORBID_DEL") {
Modal.warning({
title:"提示",
content: "直播进行中,无法删除直播",
okText: "我知道了"
})
} else if (success || resultCode === 0) {
return response;
} else if (!options.reject) {
......
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
isWeiXin() {
const ua = navigator.userAgent.toLowerCase();
return (ua.indexOf('micromessenger') > 0) && !(/wxwork/i.test(navigator.userAgent));
},
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);
},
isMac() {
const ua = navigator.platform.toLowerCase();
return ua.indexOf("mac") > 0
}
};
......@@ -2,7 +2,7 @@
* @Author: wufan
* @Date: 2021-05-11 10:21:37
* @LastEditors: Please set LastEditors
* @LastEditTime: 2021-07-19 15:24:27
* @LastEditTime: 2021-07-21 14:25:37
* @Description: 企业微信api
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*
......@@ -36,24 +36,27 @@ export default class WechatApi {
url: params.url,
}).then((result2) => {
const res2 = result2.result;
this.agentConfig({
corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat'],
success: (res) => {
console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData);
resolve(res);
},
fail: (err) => {
console.log(1213545344545)
console.log(err, 'err-agentconfig');
reject(err);
},
});
setTimeout(() => {
this.agentConfig({
corpid: res2.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致
agentid: res2.agentid, // 必填,企业微信的应用id (e.g. 1000247)
timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat', 'startLiving', 'replayLiving'],
success: (res) => {
console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData);
resolve(res);
},
fail: (err) => {
console.log(1213545344545)
console.log(err, 'err-agentconfig');
reject(err);
},
});
}, 500)
});
})
......@@ -77,7 +80,7 @@ export default class WechatApi {
timestamp: res2.timestamp, // 必填,生成签名的时间戳
nonceStr: res2.nonceStr, // 必填,生成签名的随机串
signature: res2.signature, // 必填,签名,见附录-JS-SDK使用权限签名算法
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat'],
jsApiList: ['selectExternalContact', 'getCurExternalContact', 'getContext', 'shareToExternalContact', 'sendChatMessage', 'shareToExternalChat', 'startLiving', 'replayLiving'],
success: (res) => {
console.log(res, 'res-agentconfig');
console.info('window.WWOpenData', window.WWOpenData);
......@@ -144,4 +147,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 {
}
// ant badge改小
.ant-badge {
transform: translate(-8px, -8px) scale(0.7) !important;
}
// .ant-badge {
// transform: translate(-8px, -8px) scale(0.7) !important;
// }
.ant-select-selection {
border-color: @xm-color-border !important;
......
......@@ -1704,4 +1704,24 @@ input:focus {
.ant-tag-blue{
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);
},
isMac() {
const ua = navigator.platform.toLowerCase();
return ua.indexOf("mac") >= 0
}
};
\ 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";
export function fetchLecturerData(params: object) {
return Service.Hades("public/courseCloud/queryTeacherVisitData", params);
}
export function fetchWorkWXLecturerData(params: object) {
return Service.Hades("public/courseCloud/queryWechatLiveTeacherData", params);
}
export function getQrcode(params: object) {
return Service.Sales("public/businessShow/convertShortUrls", params);
}
......@@ -19,11 +22,18 @@ export function getQrcode(params: object) {
export function fetchUserData(params: object) {
return Service.Hades("public/courseCloud/queryStudentVisitData", params);
}
export function fetchWorkWXUserData(params: object) {
return Service.Hades("public/courseCloud/queryWechatLiveStudentData", params);
}
export function createLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/createLiveCloudCourse", params);
}
export function createWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/createWechatLiveCourse", params);
}
export function getLiveCloudCoursePage(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCoursePage", params);
}
......@@ -32,6 +42,10 @@ export function exportStudentCourseData(params: object) {
return Service.Hades("public/courseCloud/exportCourseCloudVisitorAsync", params);
}
export function exportWorkWXStudentCourseData(params: object) {
return Service.Hades("public/courseCloud/exportWechatLiveStudentData", params);
}
export function exportPlayBackCourseData(params: object) {
return Service.Hades("public/courseCloud/exportCourseCloudPlayBackSync", params);
}
......@@ -42,16 +56,27 @@ export function getLiveCloudCourseDetail(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCourseDetail", params);
}
export function getWorkWXLiveCourseDetail(params: object) {
return Service.Hades("public/courseCloud/getWechatLiveCourseDetail", params)
}
export function updateLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/updateLiveCloudCourse", params);
}
export function updateWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/editWechatLiveCourse", params);
}
export function turnOnOrOffLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/turnOnOrOffLiveCloudCourse", params);
}
export function delLiveCloudCourse(params: object) {
return Service.Hades("public/courseCloud/delLiveCloudCourse", params);
}
export function delWorkWXLiveCourse(params: object) {
return Service.Hades("public/courseCloud/delWechatLiveCourse", params);
}
//该接口主要用于培训计划关联直播课的接口(会筛选掉已关联的直播课)
export function getLiveCloudCourseBasePage(params: object) {
return Service.Hades("public/courseCloud/getLiveCloudCourseBasePage", params);
......
......@@ -10,7 +10,7 @@ import {
fetchLecturerData, getCategoryTree, knowledgeMediaCoursePage, fetchUserData, exportStudentCourseData, exportPlayBackCourseData, fetchPlaybackList, createLiveCloudCourse, getLiveCloudCoursePage,
getLiveCloudCourseDetail, updateLiveCloudCourse, turnOnOrOffLiveCloudCourse, delLiveCloudCourse, changeVideoShelfState, createVideoSchedule, delVideoSchedule,
editVideoSchedule, userWatchInfo, videoSchedulePage, videoScheduleDetail, videoWatchInfo, getQrcode, getLiveCloudCourseBasePage, videoScheduleBasePage, relatedCourseToPlan,
lineDetailWatchInfo
lineDetailWatchInfo, createWorkWXLiveCourse, fetchWorkWXLecturerData, fetchWorkWXUserData, getWorkWXLiveCourseDetail, updateWorkWXLiveCourse, delWorkWXLiveCourse, exportWorkWXStudentCourseData
} from '@/data-source/course/request-api';
export default class courseService {
......@@ -18,6 +18,10 @@ export default class courseService {
static fetchLecturerData(params: any) {
return fetchLecturerData(params);
}
// 获取企微讲师上课数据
static fetchWorkWXLecturerData(params: any) {
return fetchWorkWXLecturerData(params);
}
// 生成二维码
static getQrcode(params: any) {
......@@ -28,17 +32,29 @@ export default class courseService {
static fetchUserData(params: any) {
return fetchUserData(params);
}
// 获取企微学员上课数据
static fetchWorkWXUserData(params: any) {
return fetchWorkWXUserData(params);
}
static createLiveCloudCourse(params: any) {
return createLiveCloudCourse(params);
}
//创建企微直播课
static createWorkWXLiveCourse(params: any) {
return createWorkWXLiveCourse(params)
}
static getLiveCloudCoursePage(params: any) {
return getLiveCloudCoursePage(params);
return getLiveCloudCoursePage({...params,terminalTypeEnum:"B_WEB"});
}
// 导出学生上课数据
static exportStudentCourseData(params: any) {
return exportStudentCourseData(params);
}
// 导出企微学生上课数据
static exportWorkWXStudentCourseData(params: any) {
return exportWorkWXStudentCourseData(params);
}
// 导出回放数据
static exportPlayBackCourseData(params: any) {
......@@ -53,15 +69,27 @@ export default class courseService {
static getLiveCloudCourseDetail(params: any) {
return getLiveCloudCourseDetail(params);
}
//获取企微直播详情
static getWorkWXLiveCourseDetail(params: any) {
return getWorkWXLiveCourseDetail(params);
}
static updateLiveCloudCourse(params: any) {
return updateLiveCloudCourse(params);
}
//编辑企微直播
static updateWorkWXLiveCourse(params: any) {
return updateWorkWXLiveCourse(params);
}
static turnOnOrOffLiveCloudCourse(params: any) {
return turnOnOrOffLiveCloudCourse(params);
}
static delLiveCloudCourse(params: any) {
return delLiveCloudCourse(params);
}
//删除企微直播
static delWorkWXLiveCourse(params: any) {
return delWorkWXLiveCourse(params);
}
static changeVideoShelfState(params: any) {
return changeVideoShelfState(params);
}
......
declare module 'jquery'
declare module 'cropper'
declare module 'ExamShareModal'
declare module 'routeHooks'
// declare var this: any
\ No newline at end of file
......@@ -23,6 +23,7 @@ import '@/core/xmTD';
import User from '@/common/js/user';
import Service from "@/common/js/service";
import BaseService from '@/domains/basic-domain/baseService';
import routeHook from '@/core/routeHook'
import {brandName,BRAND,brandIcon} from '@/domains/brand/constants'
declare var getParameterByName: any;
......@@ -39,7 +40,16 @@ document.head.appendChild(linkzh);
window.RCHistory = _.extend({}, history, {
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) => {
history.push(obj)
......@@ -47,13 +57,22 @@ window.RCHistory = _.extend({}, history, {
pushStateWithStatus: (obj: any) => {
history.push(obj)
},
goBack: history.goBack,
goBack: () => {
console.log(routeHook.getCallbackNum(), 'routeHook.getCallbackNum()')
history.goBack()
},
location: history.location,
replace: (obj: any) => {
history.replace(obj)
}
});
window.onhashchange = () => {
console.log(132121)
routeHook.cancel()
}
function mount() {
ReactDOM.render(
<RootRouter />,
......@@ -81,19 +100,19 @@ if (getParameterByName('code') && isWeiXin()) {
window.currentStoreUserInfo.enterpriseId = res.result.enterpriseId;
mount()
})
} else if(getParameterByName('from') === 'customer' && getParameterByName('enterpriseId') && getParameterByName('userId')){
} else if (getParameterByName('from') === 'customer' && getParameterByName('enterpriseId') && getParameterByName('userId')) {
User.setCustomerStoreId(getParameterByName('storeId'));
getWXWorkLoginNoCheck(getParameterByName('enterpriseId'),getParameterByName('userId')); //从C端跳转过来的学院自动执行免登录
}else{
getWXWorkLoginNoCheck(getParameterByName('enterpriseId'), getParameterByName('userId')); //从C端跳转过来的学院自动执行免登录
} else {
mount()
}
function getWXWorkLoginNoCheck(enterpriseId:string,userId:string) {
function getWXWorkLoginNoCheck(enterpriseId: string, userId: string) {
const params = {
appTermEnum: 'XIAOMAI_CLOUD_CLASS_PC_WEB_ADMIN',
enterpriseId,
userId,
};
BaseService.getWXWorkLoginNoCheck(params).then((res:any) => {
BaseService.getWXWorkLoginNoCheck(params).then((res: any) => {
User.setUserId(res.result.loginInfo.userId)
User.setToken(res.result.loginInfo.xmToken)
User.setEnterpriseId(res.result.enterpriseId)
......
......@@ -42,6 +42,7 @@ function CourseCatalogSelect(props) {
return (
<TreeSelect
className={props.className}
treeNodeLabelProp='categoryName'
showSearch={showSearch}
treeNodeFilterProp={treeNodeFilterProp}
......
......@@ -21,6 +21,7 @@ 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';
......@@ -110,6 +111,7 @@ class AddLive extends React.Component {
}
componentDidMount() {
routeHook.addSaveCase();
const { type } = this.state;
if (type === 'edit') {
this.getCourseDetail();
......@@ -370,6 +372,7 @@ class AddLive extends React.Component {
CourseService.createLiveCloudCourse(params).then((res) => {
if (res.success) {
message.success('新建成功');
routeHook.cancel()
window.RCHistory.push({
pathname: `/live-course`,
});
......@@ -385,6 +388,7 @@ class AddLive extends React.Component {
CourseService.updateLiveCloudCourse(params).then((res) => {
if (res.success) {
message.success('更新成功');
routeHook.cancel()
window.RCHistory.push({
pathname: `/live-course`,
});
......@@ -515,19 +519,12 @@ class AddLive extends React.Component {
// 比较state的addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo和默认数据是否相等
const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo } = this.state;
if (!_.isEqual(addLiveBasicInfo, defaultBasicInfo) || !_.isEqual(addLiveClassInfo, defaultClassInfo) || !_.isEqual(addLiveIntroInfo, defaultIntroInfo)) {
Modal.confirm({
title: '确定要返回吗?',
content: '返回后,本次编辑的内容将不被保存',
okText: '确认返回',
cancelText: '留在本页',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
window.RCHistory.push({
pathname: `/live-course`,
});
},
console.log('ghjklkjh')
window.RCHistory.push({
pathname: `/live-course`,
});
} else {
routeHook.cancel()
window.RCHistory.push({
pathname: `/live-course`,
});
......
......@@ -2,7 +2,7 @@ import User from '@/common/js/user';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import CourseService from '@/domains/course-domain/CourseService';
import { Button, message, Popover, Spin } from 'antd';
import { Button, message, Popover, Spin, Tooltip } from 'antd';
import React from 'react';
import { withRouter } from 'react-router-dom';
import dealTimeDuration from '../utils/dealTimeDuration';
......@@ -11,7 +11,7 @@ class DataList extends React.Component {
constructor(props) {
super(props);
const courseId = getParameterByName('id'); // 课程ID
const type = getParameterByName('type'); // 来源: 大班直播 large 互动班课 interactive
const type = getParameterByName('type'); // 来源: 大班直播 large 互动班课 interactive 企微直播 qiwei
this.state = {
type,
teacherData: [], // 老师上课数据
......@@ -39,32 +39,72 @@ class DataList extends React.Component {
current,
size,
};
CourseService.fetchUserData(params).then((res) => {
if (res.result) {
const { records = [], current, size, total } = res.result;
if (this.state.type === "qiwei") {
CourseService.fetchWorkWXUserData(params).then((res) => {
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 = () => {
const { liveCourseId } = this.state;
CourseService.fetchLecturerData({ liveCourseId }).then((res) => {
if (res.result) {
this.setState({
teacherData: res.result,
});
}
});
if (this.state.type === "qiwei") {
CourseService.fetchWorkWXLecturerData({ liveCourseId }).then((res) => {
if (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() {
const columns = [
......@@ -159,27 +199,92 @@ 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>*企业员工以企业微信通讯录为准</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',
render: (text, record) => {
//如无离开时间,就置空
return <span>{text ? dealTimeDuration(text) : '00:00:00'}</span>;
},
},
];
return this.state.type === "qiwei" ? columnsWorkWX : columns;
}
// 学员导出5.0
handleExportV5 = () => {
const { liveCourseId, storeId } = this.state;
CourseService.exportStudentCourseData({
liveCourseId: liveCourseId,
exportLiveType: 'VISITOR',
storeId,
}).then((res) => {
const link = res.result;
this.setState({
link,
if (this.state.type === "qiwei") {
CourseService.exportWorkWXStudentCourseData({
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();
} 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('导出成功!');
}
});
}
if (res.success) {
message.success('导出成功!');
}
});
};
handleCheckEnterTimes = () => {
......@@ -239,7 +344,7 @@ class DataList extends React.Component {
};
render() {
const { teacherData, studentData, current, size, total, loading, link } = this.state;
const { teacherData, studentData, current, size, total, loading, link, type } = this.state;
return (
<Spin spinning={loading}>
<a href={link} target='_blank' download id='loadExcel' style={{ position: 'absolute', left: '-10000px' }}>
......@@ -257,18 +362,22 @@ class DataList extends React.Component {
</div>
</div>
<div className='times item-block'>
<div className={`times-num ${Number(teacherData.entryNum) > 0 ? 'can-click' : ''}`}>
{Number(teacherData.entryNum) > 0 ? (
<Popover content={this.showTable()} trigger='click'>
<span className='times-num'>{teacherData.entryNum || 0}</span>
</Popover>
) : (
<span className='times-num'>{0}</span>
)}
{
type !== "qiwei" &&
<div className='times item-block'>
<div className={`times-num ${Number(teacherData.entryNum) > 0 ? 'can-click' : ''}`}>
{Number(teacherData.entryNum) > 0 ? (
<Popover content={this.showTable()} trigger='click'>
<span className='times-num'>{teacherData.entryNum || 0}</span>
</Popover>
) : (
<span className='times-num'>{0}</span>
)}
</div>
<div className='text'>进入直播间次数</div>
</div>
<div className='text'>进入直播间次数</div>
</div>
}
<div className='online-duration item-block'>
<div className='duration'>{teacherData.totalDuration ? dealTimeDuration(teacherData.totalDuration) : '00:00:00'}</div>
......
......@@ -21,6 +21,7 @@ class DataList extends React.Component {
}
render() {
const type = window.getParameterByName("type")
return (
<div className="page data-list">
<Breadcrumbs
......@@ -35,9 +36,13 @@ class DataList extends React.Component {
<CourseData></CourseData>
</Tabs.TabPane>
<Tabs.TabPane tab="回放记录" key="playbackData">
<PlaybackData></PlaybackData>
</Tabs.TabPane>
{
type !== "qiwei" &&
<Tabs.TabPane tab="回放记录" key="playbackData">
<PlaybackData></PlaybackData>
</Tabs.TabPane>
}
</Tabs>
</div>
......
......@@ -38,7 +38,7 @@
.title {
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
font-weight: 600;
color: #333333;
margin-bottom: 16px;
position: relative;
......@@ -84,6 +84,7 @@
background: #ffffff;
border: 1px solid #e8e8e8;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 32px;
.item-block {
......
......@@ -28,7 +28,8 @@ class AddLiveBasic extends React.Component {
showSelectFileModal: false,
cutImageBlob: null,
hasImgReady: false, // 图片是否上传成功
cropperInstace: null,
cropperInstace:null,
courseNameLimit: props.courseNameLimit?props.courseNameLimit:40
}
}
componentWillUnmount() {}
......@@ -105,21 +106,30 @@ class AddLiveBasic extends React.Component {
<span className='label'>
<span className='require'>*</span>课程名称:
</span>
<div id="courseName" style={{display:"inline-block"}}>
<Input
className={_.find(this.props.exItems,(item)=>{return item === "courseName"})?"err":""}
value={courseName}
placeholder='请输入直播名称(40字以内)'
maxLength={40}
placeholder={`请输入直播名称(${this.state.courseNameLimit}字以内)`}
maxLength={this.state.courseNameLimit}
style={{ width: 240 }}
onChange={(e) => {
this.props.onChange('courseName', e.target.value)
}}
/>
</div>
</div>
<div className='course-cover'>
<span className='label'>封面图:</span>
<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
onClick={() => {
this.setState({
......@@ -133,22 +143,20 @@ class AddLiveBasic extends React.Component {
</span>
<div className='tips'>建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。</div>
</div>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} />
</div>
</div>
</div>
<div className='course-catalog'>
<span className='label'>
<span className='require'>*</span>课程分类:
</span>
<div id="categoryId" style={{display:"inline-block"}}>
<CourseCatalogSelect
className={_.find(this.props.exItems,(item)=>{return item === "categoryId"})?"err":""}
value={categoryId}
onChange={(value, label) => {
this.handleChangeCatalogList(value, label)
}}
/>
</div>
</div>
{showSelectFileModal && (
<SelectPrepareFileModal
......
......@@ -16,7 +16,6 @@
position: relative;
.img-content {
margin-top: 8px;
margin-right: 20px;
width: 299px;
height: 169px;
......@@ -41,33 +40,56 @@
left: 8px;
}
}
}
.opt-btns {
.default-btn {
margin-left: 14px;
color: #2966ff;
cursor: pointer;
.opt-btns {
.default-btn {
margin-left: 14px;
color: #2966ff;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
}
&.disabled {
color: #ccc;
cursor: not-allowed;
}
}
.ant-upload-list {
display: none;
}
.ant-upload-list {
display: none;
}
.tips {
margin-top: 8px;
color: #999;
}
.tips {
margin-top: 8px;
color: #999;
}
}
}
.course-catalog {
margin: 20px 0 0 14px;
}
//输入框异常项
.err.ant-input:hover {
border-color: #FF4F4F;
}
.err.ant-input:focus {
border-color: #FF4F4F !important;
box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
}
.err.ant-input {
border-color: #FF4F4F;
}
//下拉选择异常项
.err.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) .ant-select-selector {
border-color: #FF4F4F;
box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
}
.err.ant-select:not(.ant-select-disabled):hover {
.ant-select-selector {
border-color: #FF4F4F;
}
}
.err.ant-select:not(.ant-select-customize-input) .ant-select-selector {
border-color: #FF4F4F;
}
}
.ant-cascader-menu-item-active:not(.ant-cascader-menu-item-disabled) {
font-weight: normal !important;
......
......@@ -75,7 +75,7 @@ class AddLiveClass extends React.Component {
// 获取助教老师列表
getAssistantList = (current = 1, selectList) => {
const { assistantQuery,assistantList} = this.state;
const { assistantStoreUserId } = this.props.data;
const { assistantStoreUserId } = this.props.data ? this.props.data:[];
const idList = selectList ? selectList : assistantStoreUserId;
const _query = {
...assistantQuery,
......
.AddLiveClassInfoWorkWX {
margin-left: 16px;
margin-bottom: 98px;
.remind-time {
.ant-select-single.ant-select-show-arrow .ant-select-selection-placeholder {
color: #333333;
}
}
.item {
margin: 24px 0;
.label {
display: inline-block;
text-align: right;
width: 100px;
.require {
color: red;
}
}
//日期时间选择异常项
.err.ant-picker-focused {
border-color: #FF4F4F;
box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
}
.err.ant-picker:hover {
border-color: #FF4F4F;
}
.err.ant-picker {
border-color: #FF4F4F;
}
}
.introduce {
display: flex;
}
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
color: #2966FF;
}
// .eerr .ant-select-focused:not(.ant-select-disabled) .ant-select:not(.ant-select-customize-input) {
// .ant-select-selector {
// border-color: red;
// box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
// }
// }
// .eerr .ant-select:not(.ant-select-disabled):hover {
// .ant-select-selector {
// border-color: red;
// }
// }
//下拉选择异常项
.err.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) .ant-select-selector {
border-color: #FF4F4F;
box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
}
.err.ant-select:not(.ant-select-disabled):hover {
.ant-select-selector {
border-color: #FF4F4F;
}
}
.err.ant-select:not(.ant-select-customize-input) .ant-select-selector {
border-color: #FF4F4F;
}
//输入框异常项
.err.ant-input:hover {
border-color: #FF4F4F;
}
.err.ant-input:focus {
border-color: #FF4F4F;
box-shadow: 0 0 0 2px rgba(255,0,0,0.2);
}
.err.ant-input {
border-color: #FF4F4F;
}
}
\ No newline at end of file
......@@ -136,7 +136,7 @@ class AddLiveIntro extends React.Component {
<span className='label'>观看设置:</span>
<div className='content'>
<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 className='warmup'>
......
import React, { useState, useRef, useEffect, useContext } from 'react'
import { Route, withRouter } from 'react-router-dom';
import Breadcrumbs from "@/components/Breadcrumbs";
import moment from 'moment'
import { Form, Alert, Input, Button, InputNumber, DatePicker, Select, Radio, message, Modal } from 'antd';
import Service from "@/common/js/service";
import User from "@/common/js/user";
declare var wx: any;
const { Option } = Select;
const courseType = {
0: '通用直播',
1: '小班课',
2: '大班课',
3: '企业培训',
4: '活动直播'
}
function CerateQWCourse(props: any) {
const [courseName, setCourseName] = useState('');
const [liveDuration, setLiveDuration] = useState(60);
const [liveStart, setLiveStart] = useState(0);
const [type, setType] = useState('0');
function handleSave() {
const param = {
courseName,
description: '直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节直播的简介,最多支持300个字节',
liveDuration: liveDuration * 60 * 100,
liveStart,
remindTime: 1000 * 60 * 10,
storeId: User.getStoreId(),
storeUserId: User.getStoreUserId(),
type: parseInt(type)
}
Service.Hades('anon/hades/wxWorkCreateLiveDemo', param).then((res) => {
wx.invoke('startLiving', {
"livingId": res.result,
}, function (res: any) {
if (res.err_msg == "startLiving:ok") {
// livingId = res.livingId;
}
});
})
}
return <div className="page createQWCourse ">
<Breadcrumbs navList={props.type === 'edit' ? "编辑考试" : "新建直播课"} goBack={props.history.goBack} />
<div className="box">
<div className="form">
<div className="title">直播信息</div>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
>
<Form.Item label="课程名称"
required>
<Input value={courseName} onChange={(e) => { setCourseName(e.target.value) }} style={{ width: 200 }} ></Input>
</Form.Item>
<Form.Item label="持续时长"
required>
<InputNumber value={liveDuration} max={1440} min={1} onChange={(value: any) => { setLiveDuration(parseInt(value) as any) }} style={{ width: 100 }} />
</Form.Item>
<Form.Item label="开始时间"
required>
<DatePicker
format="YYYY/MM/DD HH:mm"
value={liveStart ? moment(Number(liveStart)) : null}
style={{ width: 200 }}
placeholder="开始时间"
showTime
onChange={(date: any) => { setLiveStart(date ? date.valueOf() : 0) }}
/>
</Form.Item>
<Form.Item label="直播的类型"
required>
<Select value={type} placeholder="请选直播的类型" style={{ width: 200 }} onChange={(val) => {
setType(val)
}} >
{
Object.keys(courseType).map((key: any) => {
return <Option value={key}>{(courseType as any)[key]}</Option>
})
}
</Select>
</Form.Item>
</Form>
</div>
</div>
<div className="footer">
<Button onClick={props.history.goBack}>取消</Button>
<Button type="primary" onClick={handleSave}>保存</Button>
</div>
</div>
}
export default withRouter(CerateQWCourse);
\ No newline at end of file
.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:25px;
}
.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 = {
teacherId: null,
courseState: null,
shelfState: null,
thirdPartType: null
}
const defaultTeacherQuery = {
size: 10,
......@@ -50,6 +51,7 @@ class LiveCourseFilter extends React.Component {
current,
size: 10,
}
StoreService.getStoreUserBasicPage(_query).then((res) => {
const { result = {} } = res
const { records = [], total = 0, hasNext } = result
......@@ -150,6 +152,7 @@ class LiveCourseFilter extends React.Component {
courseState: undefined,
current: 1,
shelfState: null,
thirdPartType: null
},
},
() => {
......@@ -159,7 +162,7 @@ class LiveCourseFilter extends React.Component {
}
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 { teacherId: _teahcerId } = {}
const isTeacher = !!_teahcerId // 判断是否是老师身份
......@@ -199,7 +202,7 @@ class LiveCourseFilter extends React.Component {
</div>
{User.getUserRole() !== 'CloudLecturer' && (
<div className='search-condition__item'>
<span>讲师:</span>
<span style={{width:"70px",display:"inline-block",textAlign:"right"}}>讲师:</span>
<Select
placeholder='请选择讲师'
style={{ width: 'calc(100% - 70px)' }}
......@@ -295,6 +298,37 @@ class LiveCourseFilter extends React.Component {
</Select>
</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 className='reset-fold-area'>
......
......@@ -9,22 +9,57 @@
import React from 'react';
import { Button, Modal, message } from 'antd';
import Service from '@/common/js/service';
import { withRouter ,Route} from "react-router-dom";
import './liveCourseOpt.less';
import BaseService from "@/domains/basic-domain/baseService";
import CreateWorkWXCourse from './CreateWorkWXCourse'
import User from '@/common/js/user'
import LiveModeSelect from './LiveModeSelect';
class LiveCourseOpt extends React.Component {
constructor(props) {
super(props);
this.state = {
isMac: /macintosh|mac os x/i.test(navigator.userAgent),
showModeSelect: false,
}
}
handleCreateLiveCouese = () => {
window.RCHistory.push({
pathname: '/create-live-course?type=add',
handleCreateLiveCouese = ()=>{
this.setState({
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 = () => {
const { isMac } = this.state;
......@@ -48,18 +83,22 @@ class LiveCourseOpt extends React.Component {
}
render() {
const userRole = User.getUserRole();
const userRole = User.getUserRole();
const { match } = this.props;
return (
<div className="live-course-opt">
<LiveModeSelect onClose={this.onModeSelectClose} onSelected={this.onModeSelected} isShow={this.state.showModeSelect}/>
<div className="opt__left">
{userRole !== "CloudLecturer" &&
<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>
<Route path={`${match.url}/createqwcourse`} component={CreateWorkWXCourse} />
</div>
)
}
}
export default LiveCourseOpt;
\ No newline at end of file
export default withRouter(LiveCourseOpt);
\ 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 {
];
const { list, scanFileModal, editData, cancelObject, showSelectFileModal, selectedFileList, diskList, showPreviewModal, previewStatus, url } = this.state;
const _list = _.reject(list, (item) => cancelObject[item.id]);
const { thirdPartType } = this.props.data
return (
<Modal
visible={true}
......@@ -348,10 +349,17 @@ class ManageCoursewareModal extends React.Component {
{_.isEmpty(_list) ? (
<div className='empty-body'>
<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>
<p className='empty-tip'>提前上传直播需要的课件和素材,直播将会变得更便捷!</p>
{ thirdPartType !== "WECHAT" && <p className='empty-tip'>提前上传直播需要的课件和素材,直播将会变得更便捷!</p>}
</div>
) : (
<div className='manage-body'>
......
......@@ -11,6 +11,14 @@
width:150px;
height:150px;
}
.qiwei-tip {
font-size: 14px;
font-weight: 400;
color: #999;
text-align: center;
margin-top: 12px;
margin-bottom: 12px;
}
.empty-button {
display: block;
margin: 0 auto 8px;
......
......@@ -107,47 +107,56 @@ class PreviewCourseModal extends React.Component {
timeHorizonStart,
timeHorizonEnd,
teacherName,
duration
} = courseClassInfo;
const { introduce, categoryName } = courseIntroInfo;
let { activeTab } = this.state;
let liveDateStr, startTimeStr, endTimeStr;
if (type === "add") {
const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD");
console.log("_liveDate", _liveDate);
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;
if (this.props.bizType === "qiwei") {
let _startTime = startTime === 0 ? moment().valueOf():startTime
startTimeStr = moment(_startTime).format("YYYY-MM-DD HH:mm")
endTimeStr = moment(endTime === 0?moment(_startTime+Number(duration)*1000).valueOf():endTime).format("HH:mm")
console.log(duration)
} 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;
if (type === "add") {
const _liveDate = moment(calendarTime[0]).format("YYYY-MM-DD");
console.log("_liveDate", _liveDate);
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 {
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 (
<Modal
title="预览"
......
......@@ -60,10 +60,12 @@
.title__state {
min-width: 40px;
height: 17px;
padding: 0px 8px;
padding-left: 8px;
padding-right: 8px;
border-radius: 10px;
margin-left: 6px;
font-size: 12px;
line-height: 17px;
color: #FFF;
background-color: #34B88B;
}
......
......@@ -102,7 +102,7 @@ class ShareLiveModal extends React.Component {
render() {
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;
// 判断是否是默认图, 默认图不需要在URL后面增加字符串
let coverImgSrc = '';
......@@ -188,8 +188,8 @@ class ShareLiveModal extends React.Component {
<div className='right'>
<div className='share-poster right__item'>
<div className='title'>① 海报分享</div>
{type === 'liveClass' && <div className='sub-title'>学员可通过微信扫描海报二维码,观看{title}</div>}
{type === 'videoClass' && <div className='sub-title'>学员可通过微信识别二维码,报名观看{title}</div>}
{type === 'liveClass' && <div className='sub-title'>学员可通过微信{thirdPartType === "WECHAT"?"/企业微信":""}扫描海报二维码,观看{title}</div>}
{type === 'videoClass' && <div className='sub-title'>学员可通过微信{thirdPartType === "WECHAT"?"/企业微信":""}识别二维码,报名观看{title}</div>}
<div className='content' onClick={_.debounce(this.handleDownloadPoster, 1000, true)}>
下载海报
......@@ -198,7 +198,7 @@ class ShareLiveModal extends React.Component {
<div className='share-url right__item'>
<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>}
<div className='content url-content'>
<div className='share-url' id='shareUrl'>
......
......@@ -309,7 +309,6 @@ class SelectOperatorModal extends React.Component {
),
key: 'course',
dataIndex: 'course',
width: '40%',
render: (val, record) => {
let hasCover = false;
return (
......@@ -341,7 +340,7 @@ class SelectOperatorModal extends React.Component {
title: '上课时间',
key: 'courseTime',
dataIndex: 'courseTime',
width: '40%',
width: 150,
render: (val, record) => {
return (
<div>
......@@ -357,7 +356,7 @@ class SelectOperatorModal extends React.Component {
title: '学院展示',
key: 'shelfState',
dataIndex: 'shelfState',
width: '20%',
width: 120,
render: (val, record) => {
return (
<span>
......
......@@ -16,11 +16,10 @@ import User from '@/common/js/user';
import BaseService from "@/domains/basic-domain/baseService";
import moment from 'moment';
import { VersionContext, VersionInfo, XMContext } from '@/store/context';
import WechatApi from '@/common/js/wechatApi';
import { setStoreGroupPermission, setStorePermission, setStoreGroupList, setStoreList, setWechatLogin } from '@/store/actions/index';
import Service from "@/common/js/service";
import Bus from '@/core/tbus';
import WechatApi from '@/common/js/wechatApi';
import { func } from 'prop-types';
const { Footer, Sider, Content } = Layout;
......
import React , { useContext, useEffect ,useState}from 'react'
import React, { useContext, useEffect, useState } from 'react'
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',showModal )
return ()=>{
Bus.unbind('showRouteChangeModal',showModal)
}
}, [])
function showModal(){
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 (
<div
className={menuType ? `right-container has-nav` : `right-container has-nav right-container-vertical`}
id="rightContainer"
>
<MainRoutes/>
<RedirectRoutes/>
<MainRoutes />
<RedirectRoutes />
</div>
)
}
......
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 qrcode from "@/libs/qrcode/qrcode.js";
import { PATH } from '@/domains/basic-domain/constants';
import { corpType } from '@/domains/brand/constants'
import './WechatLogin.less';
......@@ -9,6 +9,7 @@ import { brandName, BRAND, brandIcon, brandLogo } from '@/domains/brand/constant
declare var location: any;
declare var window: any;
export default function WechatLogin(props: any) {
const freshTime = 60;
const init: any = null;
......
......@@ -18,22 +18,6 @@ import _ from 'underscore';
import SwitchRoute from '@/modules/root/SwitchRoute';
import ErrorCollege from '@/modules/root/ErrorCollege';
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 = () => {
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