Commit 2fb7a489 by maolipeng

feat:新增企微直播

parent cb748593
......@@ -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;
......
......@@ -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);
}
......
......@@ -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
} 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,9 +32,17 @@ 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);
}
......
......@@ -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,6 +39,21 @@ class DataList extends React.Component {
current,
size,
};
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;
......@@ -52,10 +67,21 @@ class DataList extends React.Component {
});
}
});
}
};
// 获取老师上课数据
fetchLecturerData = () => {
const { liveCourseId } = this.state;
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({
......@@ -63,6 +89,8 @@ class DataList extends React.Component {
});
}
});
}
};
// 进入直播次数列表
......@@ -233,7 +261,7 @@ class DataList extends React.Component {
},
];
return columns;
return this.state.type === "qiwei" ? columnsWorkWX : columns;
}
// 学员导出5.0
handleExportV5 = () => {
......
import React, { useEffect, useState } from "react";
import { DatePicker, Select } from 'antd';
import { DatePicker, TimePicker, Select } from 'antd';
import StoreService from "@/domains/store-domain/storeService";
import "./AddLiveClassInfoWorkWX.less";
import GraphicsEditor from "./GraphicsEditor";
import moment from "moment";
const { Option } = Select;
const defaultTeacherQuery = {
......@@ -16,26 +17,65 @@ export default function AddLiveClassInfoWorkWX(props) {
const [teacherQuery, setTeacherQuery] = useState(defaultTeacherQuery)
const [teacherList, setTeacherList] = useState([])
const [introduce, setIntroduce] = useState()
const [duration, setDuration] = useState(0)
const [cusTime, setCusTime] = useState(false)
const [beginDate, setBeginDate] = useState(moment().startOf('day').valueOf())
const [endDate, setEndDate] = useState(moment().startOf('day').valueOf())
useEffect(()=> {
getTeacherList()
},[])
//开始时间
function onBeginDateChange(date, dateString) {
setBeginDate(date.startOf('day').valueOf())
}
function onBeginDateOK(date) {
console.log(date)
}
function onBeginTimeChange(date, dateString) {
props.onChange("beginTime",date.valueOf())
// props.onChange("beginTime",date.valueOf())
}
function onBeginTimeOK(time) {
props.onChange("beginTime",beginDate+(time.hour()*60+time.minute())*60*1000)
}
//结束时间
function onEndDateChange(date, dateString) {
setEndDate(date.startOf('day').valueOf())
}
function onEndDateOK(date) {
}
function onBeginTimeOK() {
function onEndTimeChange(date, dateString) {
// props.onChange("endTime",date.valueOf())
}
function onEndTimeOK(time) {
props.onChange("endTime",endDate+(time.hour()*60+time.minute())*60*1000)
}
function onDurationChange(value, option) {
if (value === "0") {
setCusTime(true)
return
}
let d = Number(value)*60*1000;
setDuration(d)
props.onChange("duration",d)
}
function onTeacherChange(value, option) {
props.onChange("teacherId",value)
}
function onRemindChange(value, option) {
props.onChange("remindTime",Number(value)*60)
}
function onChangeIntro(val) {
......@@ -61,21 +101,36 @@ export default function AddLiveClassInfoWorkWX(props) {
<div className="AddLiveClassInfoWorkWX">
<div className="begin-time item">
<span className="label"><span className="require">*</span>开始时间:</span>
<DatePicker showTime onChange={onBeginTimeChange} onOk={onBeginTimeOK} />
<DatePicker defaultValue={moment()} onChange={onBeginDateChange} onOk={onBeginDateOK} />
<TimePicker defaultValue={moment()} onChange={onBeginTimeChange} onOk={onBeginTimeOK} format="HH:mm" />
</div>
<div className="duration-time item">
{
cusTime ? (
<>
<span className="label"><span className="require">*</span>结束时间:</span>
<DatePicker defaultValue={moment()} onChange={onEndDateChange} onOk={onEndDateOK} />
<TimePicker defaultValue={moment()} onChange={onEndTimeChange} onOk={onEndTimeOK} format="HH:mm" />
</>
) : (
<>
<span className="label"><span className="require">*</span>时长:</span>
<Select onChange={onDurationChange} defaultValue="60">
<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>
<Select
onChange={onDurationChange}
onChange={onTeacherChange}
style={{width:"240px"}}
placeholder="请选择讲师"
>
......
......@@ -36,38 +36,19 @@ const defaultBasicInfo = {
courseName: '', // 课程名称
coverUrl: defaultCover,
coverId: '',
categoryId: '',
categoryName: '',
categoryId: null,
}
const defaultClassInfo = {
categoryId: '',
teacherId: '', //讲师的Id
teacherName: '',
liveDate: 0,
timeHorizonStart: 0,
timeHorizonEnd: 0,
calendarTime: [],
courseName: '', //课程名称
duration: 3600000, //直播时长默认1小时
remindTime: 0, //提醒时间
startTime: new Date().getTime() + 300000,
endTime: new Date().getTime() + 300000,
};
// const defaultIntroInfo = {
// needRecord: 'YES',
// whetherVisitorsJoin: 'NO',
// liveCourseWarmMedia: {},
// // 讲师简介
// liveCourseMediaRequests: [
// {
// contentType: 'INTRO',
// mediaType: 'TEXT',
// mediaContent: '',
// key: Math.random(),
// },
// ],
// };
function CreateWorkWXCourse() {
const [id, setId] = useState(getParameterByName('id'))
const [type,setType] = useState(getParameterByName('type'))
......@@ -76,44 +57,11 @@ function CreateWorkWXCourse() {
const [courseState, setCourseState] = useState('UN_START')
const [editorTextLength, setEditorTextLength] = useState(0)
const [loadintroduce, setLoadintroduce] = useState(false)
const [addLiveBasicInfo, setAddLiveBasicInfo] = useState(defaultBasicInfo)
const [addLiveClassInfo, setAddLiveClassInfo] = useState()
const [addLiveIntroInfo, setAddLiveIntroInfo] = useState({})
const [basicInfo, setBasicInfo] = useState(defaultBasicInfo)
const [classInfo, setClassInfo] = useState(defaultClassInfo)
const [endTime, setEndTime] = useState(0)
const [introduce, setIntroduce] = useState('')
const [previewLiveCourseModal, setPreviewLiveCourseModal] = useState()
// this.state = {
// // 直播课基本信息
// addLiveBasicInfo: {
// courseName: null, // 课程名称
// coverUrl: defaultCover,
// coverId: null,
// categoryId: null,
// categoryName: null,
// },
// // 直播课上课信息
// addLiveClassInfo: {
// teacherId: null,
// teacherName: null,
// assistant: [],
// assistantStoreUserId: [],
// assistantNames: [],
// liveDate: null,
// timeHorizonStart: null,
// timeHorizonEnd: null,
// calendarTime: [], // 批量排课
// startTime: new Date().getTime() + 300000, // 批量开始时分
// endTime: new Date().getTime() + 300000, // 批量结束时分
// },
// // 直播课简介
// addLiveIntroInfo: {
// needRecord: 'YES',
// whetherVisitorsJoin: 'NO',
// liveCourseWarmMedia: {},
// introduce: '',
// liveCourseMediaRequests: [],
// },
// };
useEffect(()=> {
routeHook.addSaveCase();
......@@ -219,6 +167,7 @@ function CreateWorkWXCourse() {
});
};
//获取简介
function getIntroduce(key, url) {
$.ajax({
data: {},
......@@ -226,10 +175,8 @@ function CreateWorkWXCourse() {
url,
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
success: (res) => {
let intro = addLiveIntroInfo
intro.introduce = res
setLoadintroduce(true)
setAddLiveIntroInfo(intro)
setIntroduce(res)
},
error: () => {
message.warning('获取简介失败');
......@@ -238,11 +185,10 @@ function CreateWorkWXCourse() {
};
// 修改基本信息
// 修改基本信息
function handleChangeBasicInfo(field, value) {
let binfo = {...addLiveBasicInfo}
let binfo = {...basicInfo}
binfo[field] = value
setAddLiveBasicInfo(binfo)
setBasicInfo(binfo)
};
// 修改上课信息
......@@ -259,17 +205,31 @@ function CreateWorkWXCourse() {
setAddLiveClassInfo(_addLiveClassInfo)
};
//课程信息变更回调
function onClassInfoChange(field, value) {
let classinfo = {...classInfo}
switch (field) {
case 'intro':
let introinfo = {...addLiveIntroInfo}
introinfo.introduce = value
setAddLiveIntroInfo(introinfo)
setIntroduce(value)
break;
case 'beginTime':
let classinfo = {...addLiveClassInfo}
classinfo.startTime = value
setAddLiveClassInfo(classinfo)
setClassInfo(classinfo)
break;
case 'endTime':
setEndTime(value)
break;
case 'duration':
classinfo.duration = value
setClassInfo(classinfo)
break;
case 'teacherId':
classinfo.teacherId = value
setClassInfo(classinfo)
break;
case 'remindTime':
classinfo.remindTime = value
setClassInfo(classinfo)
break;
default:
console.log("NULL")
......@@ -292,12 +252,7 @@ function CreateWorkWXCourse() {
});
return;
}
const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, id, isEdit, type, editorTextLength } = this.state;
const { liveDate, timeHorizonStart } = addLiveClassInfo;
const _liveDate = moment(liveDate).format('YYYY-MM-DD');
const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm');
const startTime = Number(moment(_liveDate + ' ' + _timeHorizonStart).format('x'));
if (type === 'edit' && isEdit && new Date().getTime() > startTime - 1800000) {
if (type === 'edit' && isEdit && new Date().getTime() > classInfo.startTime - 1800000) {
Modal.info({
title: '提示',
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
......@@ -311,27 +266,20 @@ function CreateWorkWXCourse() {
}
// this.handleValidate(addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, isEdit, editorTextLength).then((res) => {
// if (!res) return;
//上传简介
Upload.uploadTextToOSS(
addLiveIntroInfo.introduce,
introduce,
`${randomString()}.txt`,
(introduceId) => {
submitRemote({ introduceId, addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, id });
submitRemote({ introduceId, id });
},
() => message.warning('上传课程简介失败')
);
// });
};
function submitRemote({ introduceId, addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, id }) {
const { courseName, coverUrl, coverId, categoryId } = addLiveBasicInfo;
const { liveDate, teacherId, assistant, timeHorizonEnd, timeHorizonStart, calendarTime } = addLiveClassInfo;
let { startTime, endTime } = addLiveClassInfo;
const { needRecord, whetherVisitorsJoin, liveCourseWarmMedia } = addLiveIntroInfo;
function submitRemote({ introduceId, id }) {
if (type === 'add') {
startTime = startTime;
endTime = endTime;
} else {
const _liveDate = moment(liveDate).format('YYYY-MM-DD');
const _timeHorizonStart = moment(timeHorizonStart).format('HH:mm');
......@@ -340,41 +288,19 @@ function CreateWorkWXCourse() {
endTime = moment(_liveDate + ' ' + _timeHorizonEnd).format('x');
}
let coverObj = {
contentType: 'COVER',
mediaContent: coverId,
mediaType: 'PICTURE',
mediaUrl: coverUrl,
};
let scheduleMediaRequests = [];
if (coverId) {
scheduleMediaRequests = [coverObj, ...scheduleMediaRequests];
}
if (liveCourseWarmMedia && liveCourseWarmMedia.mediaUrl) {
scheduleMediaRequests = [liveCourseWarmMedia, ...scheduleMediaRequests];
}
const commonParams = {
adminIds: assistant,
calendarTime,
categoryId,
endTime,
needRecord,
startTime,
courseName: courseName.trim(),
storeId: User.getStoreId(),
teacherId: teacherId,
whetherVisitorsJoin,
scheduleMediaRequests,
};
if (type === 'add') {
if (endTime !== 0) {
classInfo.duration = endTime - classInfo.startTime
}
const params = {
...commonParams,
operatorId: User.getUserId(),
...classInfo,
operatorId:User.getUserId(),
introduceId,
storeId: User.getStoreId(),
...basicInfo
};
CourseService.createLiveCloudCourse(params).then((res) => {
CourseService.createWorkWXLiveCourse(params).then((res) => {
if (res.success) {
message.success('新建成功');
window.RCHistory.push({
......@@ -388,6 +314,7 @@ function CreateWorkWXCourse() {
updateUserId: User.getUserId(),
liveCourseId: id,
introduceId,
storeId: User.getStoreId()
};
CourseService.updateLiveCloudCourse(params).then((res) => {
if (res.success) {
......@@ -520,7 +447,7 @@ function CreateWorkWXCourse() {
function handleGoBack() {
// 比较state的addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo和默认数据是否相等
// const { addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo } = this.state;
if (!_.isEqual(addLiveBasicInfo, defaultBasicInfo) || !_.isEqual(addLiveClassInfo, defaultClassInfo) || !_.isEqual(addLiveIntroInfo, defaultIntroInfo)) {
if (!_.isEqual(basicInfo, defaultBasicInfo) || !_.isEqual(classInfo, defaultClassInfo)) {
console.log('ghjklkjh')
window.RCHistory.push({
pathname: `/live-course`,
......@@ -537,7 +464,7 @@ function CreateWorkWXCourse() {
// const { id, type, addLiveBasicInfo, addLiveClassInfo, addLiveIntroInfo, isEdit, loadintroduce } = this.state;
return (
<div className='page CreateWorkWXCourse'>
<Breadcrumbs navList={type == 'add' ? '新建直播课' : '编辑直播课'} goBack={handleGoBack} />
<Breadcrumbs navList={type === 'add' ? '新建直播课' : '编辑直播课'} goBack={handleGoBack} />
<div className='box'>
<div className='show-tips'>
<ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
......@@ -545,7 +472,7 @@ function CreateWorkWXCourse() {
<div className='add-live-page__form'>
<div className='basic-info__wrap'>
<div className='title'>基本信息</div>
<AddLiveBasic isEdit={isEdit} pageType={type} data={addLiveBasicInfo} onChange={handleChangeBasicInfo} />
<AddLiveBasic isEdit={isEdit} pageType={type} data={basicInfo} onChange={handleChangeBasicInfo} />
</div>
<div className='class-info__wrap'>
......
......@@ -14,7 +14,7 @@ import BaseService from '@/domains/basic-domain/baseService';
import { LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService';
import { QuestionCircleOutlined } from '@ant-design/icons';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
import { Dropdown, message, Badge, Modal, Switch, Tooltip } from 'antd';
import React from 'react';
import { Route, withRouter } from 'react-router-dom';
import _ from 'underscore';
......@@ -113,9 +113,9 @@ class LiveCourseList extends React.Component {
// 前往上课数据页面
handleLinkToClassData = (item) => {
const { match } = this.props;
let type = item.thirdPartType === "WECHAT" ? "qiwei" : "large"
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 = () => {
......@@ -159,11 +159,6 @@ class LiveCourseList extends React.Component {
<span className='course-time'>
{window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))}
</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 className='teacher-assistant'>
<Choose>
......@@ -220,7 +215,11 @@ class LiveCourseList extends React.Component {
key: 'couseCatalog',
dataIndex: 'couseCatalog',
render: (val, item) => {
return <div className='categoryName'>{item.categoryName}</div>;
return <Badge
color={courseStateShow[item.courseState].color}
size="default"
text={<span style={{color:"#666666"}}>{courseStateShow[item.courseState].title}</span>}
/>;
},
},
{
......@@ -229,7 +228,7 @@ class LiveCourseList extends React.Component {
key: 'couseCatalog',
dataIndex: 'couseCatalog',
render: (val, item) => {
return <div className='categoryName'>{item.categoryName}</div>;
return <div>{item.thirdPartType === "WECHAT" ? "企微直播":"小麦直播"}</div>;
},
},
{
......@@ -465,11 +464,6 @@ class LiveCourseList extends React.Component {
<span className='course-time'>
{window.formatDate('YYYY-MM-DD H:i', parseInt(record.startTime))}~{window.formatDate('H:i', parseInt(record.endTime))}
</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 className='teacher-assistant'>
<Choose>
......
......@@ -50,7 +50,7 @@ class LiveCourseOpt extends React.Component {
})
} else if (type === 1) {
const { match } = this.props;
this.props.history.push(`${match.url}/createqwcourse`)
this.props.history.push(`${match.url}/createqwcourse?type=add`)
}
}
......
......@@ -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>
......@@ -354,10 +353,21 @@ class SelectOperatorModal extends React.Component {
},
},
{
title: '直播方式',
key: 'thirdPartType',
dataIndex: 'thirdPartType',
width: 120,
render: (val, record) => {
return (
<div>{record.thirdPartType === "WECHAT" ? "企微直播":"小麦直播"}</div>
);
},
},
{
title: '学院展示',
key: 'shelfState',
dataIndex: 'shelfState',
width: '20%',
width: 120,
render: (val, record) => {
return (
<span>
......
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