Commit 542a3ab6 by zhangleyuan

feat:联调视屏课相关模块

parent 3695560d
...@@ -30,10 +30,10 @@ class ImgCutModalNew extends React.Component { ...@@ -30,10 +30,10 @@ class ImgCutModalNew extends React.Component {
const fileName = window.random_string(16) + name.slice(name.lastIndexOf('.')); const fileName = window.random_string(16) + name.slice(name.lastIndexOf('.'));
const params = { const params = {
bizCode: bizCode, accessTypeEnum:"PUBLIC",
accessTypeEnum: 'PUBLIC', bizCode:'CLOUD_CLASS_COMMON',
instId: LS.get('instId'), instId:User.getStoreId(),
resourceName: fileName resourceName:name
} }
// 压缩 // 压缩
if (compress) { if (compress) {
...@@ -41,7 +41,7 @@ class ImgCutModalNew extends React.Component { ...@@ -41,7 +41,7 @@ class ImgCutModalNew extends React.Component {
dataUrl = this.getBase64Size(dataUrl) > compressSizeByte ? await this.handleCompressImg(dataUrl, compressSizeByte, cutWidth) : dataUrl; dataUrl = this.getBase64Size(dataUrl) > compressSizeByte ? await this.handleCompressImg(dataUrl, compressSizeByte, cutWidth) : dataUrl;
} }
const cutImage = this.convertBase64UrlToBlob(dataUrl); const cutImage = this.convertBase64UrlToBlob(dataUrl);
Service.Hades('public/hades/commonOssAuthority', param).then((res) => { Service.Hades('public/hades/commonOssAuthority', params).then((res) => {
const { resourceId, accessId, policy, callback, signature,key, host } = res.result; const { resourceId, accessId, policy, callback, signature,key, host } = res.result;
const localUrl = URL.createObjectURL(cutImage); const localUrl = URL.createObjectURL(cutImage);
// 构建上传的表单 // 构建上传的表单
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:07:47 * @Date: 2020-08-05 10:07:47
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-28 10:12:44 * @LastEditTime: 2020-12-30 17:20:19
* @Description: 视频课新增/编辑页 * @Description: 视频课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
...@@ -20,6 +20,7 @@ import SelectStudent from '../modal/select-student'; ...@@ -20,6 +20,7 @@ import SelectStudent from '../modal/select-student';
import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal'; import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal';
import PreviewCourseModal from '../modal/PreviewCourseModal'; import PreviewCourseModal from '../modal/PreviewCourseModal';
import StoreService from "@/domains/store-domain/storeService"; import StoreService from "@/domains/store-domain/storeService";
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'; import User from '@/common/js/user';
import './AddVideoCourse.less'; import './AddVideoCourse.less';
...@@ -43,13 +44,13 @@ class AddVideoCourse extends React.Component { ...@@ -43,13 +44,13 @@ class AddVideoCourse extends React.Component {
scheduleVideoId: null, // 视频课链接 scheduleVideoId: null, // 视频课链接
coverId: null, // 视频封面的recourceId coverId: null, // 视频封面的recourceId
coverUrl: null, // 视频课封面 coverUrl: null, // 视频课封面
joinType: null, // 观看模式, 默认为指定某些学员可以观看
studentList: [], // 上课学员列表 studentList: [], // 上课学员列表
shelfState:'YES', //是否开启店铺展示 shelfState:'YES', //是否开启店铺展示
scheduleMedia: [{ // 视频课媒体资源 scheduleMedia: [{ // 视频课媒体资源
contentType:"INTRO",
mediaType: 'TEXT', mediaType: 'TEXT',
mediaContent: '', mediaContent: '',
key: EDIT_BOX_KEY key: Math.random()
}], }],
diskList: [], // 机构可见磁盘目录 diskList: [], // 机构可见磁盘目录
selectedFileList: [], // 已经从资料云盘中勾选的文件 selectedFileList: [], // 已经从资料云盘中勾选的文件
...@@ -69,12 +70,12 @@ class AddVideoCourse extends React.Component { ...@@ -69,12 +70,12 @@ class AddVideoCourse extends React.Component {
this.getCourseCatalogList(); this.getCourseCatalogList();
if (pageType === 'edit') { if (pageType === 'edit') {
this.handleFetchScheudleDetail(id); this.handleFetchScheudleDetail(id);
this.handleFetchStudentList(id); // this.handleFetchStudentList(id);
} }
} }
//获取分类列表 //获取分类列表
getCourseCatalogList = ()=>{ getCourseCatalogList = ()=>{
StoreService.getCourseCatalogList({current:1,size:10}).then((res) => { StoreService.getCourseCatalogList({current:1,size:1000}).then((res) => {
this.setState({ this.setState({
courseCatalogList:res.result.records courseCatalogList:res.result.records
}) })
...@@ -96,9 +97,9 @@ class AddVideoCourse extends React.Component { ...@@ -96,9 +97,9 @@ class AddVideoCourse extends React.Component {
} }
} }
// 获取视频课详情 // 获取视频课详情
handleFetchScheudleDetail = (scheduleId) => { handleFetchScheudleDetail = (courseId) => {
window.axios.Apollo('public/apollo/getLessonScheduleDetail', { CourseService.videoScheduleDetail({
scheduleId courseId
}).then((res) => { }).then((res) => {
const { result = {} } = res || {}; const { result = {} } = res || {};
const { const {
...@@ -107,11 +108,9 @@ class AddVideoCourse extends React.Component { ...@@ -107,11 +108,9 @@ class AddVideoCourse extends React.Component {
videoType, videoType,
videoDuration, videoDuration,
videoName, videoName,
studentIds,
scheduleMedia, scheduleMedia,
courseName, courseName,
scheduleVideoId, scheduleVideoId,
joinType,
scheduleVideoUrl, scheduleVideoUrl,
} = result; } = result;
this.setState({ this.setState({
...@@ -120,11 +119,9 @@ class AddVideoCourse extends React.Component { ...@@ -120,11 +119,9 @@ class AddVideoCourse extends React.Component {
videoType, videoType,
videoName, videoName,
videoDuration, videoDuration,
studentIds,
scheduleMedia, scheduleMedia,
courseName, courseName,
scheduleVideoId, scheduleVideoId,
joinType,
scheduleVideoUrl, scheduleVideoUrl,
}); });
...@@ -132,19 +129,19 @@ class AddVideoCourse extends React.Component { ...@@ -132,19 +129,19 @@ class AddVideoCourse extends React.Component {
} }
// 获取视频课学员 // 获取视频课学员
handleFetchStudentList = (scheduleId) => { // handleFetchStudentList = (scheduleId) => {
window.axios.Apollo('public/apollo/getLessonStuIdListByScheduleId', { // window.axios.Apollo('public/apollo/getLessonStuIdListByScheduleId', {
scheduleId // scheduleId
}).then((res) => { // }).then((res) => {
const studentIds = res.result || []; // const studentIds = res.result || [];
const studentList = []; // const studentList = [];
_.each(studentIds, (item) => { // _.each(studentIds, (item) => {
studentList.push({ studentId: item }); // studentList.push({ studentId: item });
}); // });
this.setState({ studentList }) // this.setState({ studentList })
}); // });
} // }
// 获取机构可见的磁盘 // 获取机构可见的磁盘
// handleFetchDiskList = () => { // handleFetchDiskList = () => {
...@@ -317,29 +314,22 @@ class AddVideoCourse extends React.Component { ...@@ -317,29 +314,22 @@ class AddVideoCourse extends React.Component {
storeId:User.getStoreId(), storeId:User.getStoreId(),
shelfState, shelfState,
whetherVisitorsJoin whetherVisitorsJoin
}; };
// 校验必填字段:课程名称, 课程视频 // 校验必填字段:课程名称, 课程视频
this.handleValidate(courseName, scheduleVideoId, joinType, scheduleMedia).then((res) => { this.handleValidate(courseName, scheduleVideoId,categoryId, scheduleMedia).then((res) => {
if (!res) return; if (!res) return;
if (pageType === 'add') { if (pageType === 'add') {
window.axios.Apollo('public/apollo/createLessonSchedule', commonParams).then((res) => { CourseService.createVideoSchedule(commonParams).then((res) => {
if (!res) return; if (!res) return;
message.success("新建成功"); message.success("新建成功");
// localStorage.setItem('videoCourseItem', JSON.stringify({
// ...commonParams,
// coverUrl,
// scheduleVideoUrl,
// id: res.result
// }));
window.RCHistory.goBack(); window.RCHistory.goBack();
}) })
} else { } else {
const editParams = { const editParams = {
id, courseId:id,
...commonParams, ...commonParams,
} }
window.axios.Apollo('public/apollo/editLessonSchedule', editParams).then((res) => { CourseService.editVideoSchedule(editParams).then((res) => {
if (!res) return; if (!res) return;
message.success("保存成功"); message.success("保存成功");
window.RCHistory.goBack(); window.RCHistory.goBack();
...@@ -348,24 +338,29 @@ class AddVideoCourse extends React.Component { ...@@ -348,24 +338,29 @@ class AddVideoCourse extends React.Component {
}); });
} }
handleValidate = (courseName, scheduleVideoId, joinType, scheduleMedia) => { handleValidate = (courseName, scheduleVideoId,categoryId,scheduleMedia) => {
return new Promise((resolve) => { return new Promise((resolve) => {
if (!courseName) { if (!courseName) {
message.warning('请输入课程名称'); message.warning('请输入课程名称');
resolve(false); resolve(false);
} else if (!scheduleVideoId) { return false
}
if (!scheduleVideoId) {
message.warning('请上传视频'); message.warning('请上传视频');
resolve(false); resolve(false);
} else if (!joinType) { return false
message.warning('请选择观看设置'); }
if(!categoryId){
message.warning('请选择课程分类');
resolve(false); resolve(false);
} else { return false
const textMedia = scheduleMedia.filter((item) => item.mediaType === 'TEXT'); }
for (let i = 0, len = textMedia.length; i < len; i++) { const textMedia = scheduleMedia.filter((item) => item.mediaType === 'TEXT');
if (textMedia[i].mediaContentLength && textMedia[i].mediaContentLength.length > 1000) { for (let i = 0, len = textMedia.length; i < len; i++) {
message.warning(`第${i+1}个文字简介的字数超过了1000个字`); if (textMedia[i].mediaContentLength && textMedia[i].mediaContentLength.length > 1000) {
resolve(false); message.warning(`第${i+1}个文字简介的字数超过了1000个字`);
} resolve(false);
return false
} }
} }
resolve(true); resolve(true);
...@@ -471,12 +466,12 @@ class AddVideoCourse extends React.Component { ...@@ -471,12 +466,12 @@ class AddVideoCourse extends React.Component {
</div> </div>
<div className="course-catalog"> <div className="course-catalog">
<span className="label"><span className="require">*</span>课程分类:</span> <span className="label"><span className="require">*</span>课程分类:</span>
{ pageType === 'add' &&
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" />
{/* { (pageType === 'edit') &&
<Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" /> <Cascader defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" />
} } */}
{ (pageType === 'edit' && categoryName) &&
<Cascader disabled={!isEdit ? true: false} defaultValue={[categoryName]} options={courseCatalogList} displayRender={ label => label.join('-')} fieldNames={fieldNames} onChange={this.catalogChange} style={{ width: 240 }} placeholder="请选择课程分类" />
}
</div> </div>
<div className="intro-info mt16"> <div className="intro-info mt16">
<AddVideoIntro <AddVideoIntro
......
...@@ -2,18 +2,20 @@ ...@@ -2,18 +2,20 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-08-05 10:12:45 * @Date: 2020-08-05 10:12:45
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 14:10:44 * @LastEditTime: 2020-12-30 17:44:18
* @Description: 视频课-列表模块 * @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有 * @Copyright: 杭州杰竞科技有限公司 版权所有
*/ */
import React from 'react'; import React from 'react';
import { Table, Modal, message } from 'antd'; import { Table, Modal, message , Tooltip,Switch,Dropdown} from 'antd';
import { PageControl } from "@/components"; import { PageControl } from "@/components";
import { LIVE_SHARE_MAP } from '@/common/constants/academic/cloudClass'; import { LIVE_SHARE_MAP } from '@/common/constants/academic/cloudClass';
import StudentListModal from '../modal/StudentListModal'; import StudentListModal from '../modal/StudentListModal';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal'; import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import CourseService from "@/domains/course-domain/CourseService";
import User from '@/common/js/user'
import './VideoCourseList.less'; import './VideoCourseList.less';
...@@ -44,43 +46,63 @@ class VideoCourseList extends React.Component { ...@@ -44,43 +46,63 @@ class VideoCourseList extends React.Component {
title: '视频课', title: '视频课',
key: 'scheduleName', key: 'scheduleName',
dataIndex: 'scheduleName', dataIndex: 'scheduleName',
width: '25%', width: '20%',
render: (val, record) => { render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record; const { coverUrl, scheduleVideoUrl } = record;
return ( return (
<div className="record__item"> <div className="record__item">
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */} {/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className="course-cover" src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} /> <img className="course-cover" src={coverUrl || `${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`} />
<span className="course-name">{val}</span> <span className="course-name">{record.courseName}</span>
</div> </div>
) )
} }
}, },
{ {
title: '学员人数', title: '课程分类',
key: "stuNum", key: 'categoryName',
dataIndex: "stuNum", dataIndex: 'categoryName',
render: (val, record) => { render: (val, record) => {
return ( return (
<span <div className="record__item">
className="operate-text" {record.categoryName}
onClick={() => this.handleShowStudentListModal(record)} </div>
> )
{val} }
</span>
);
},
}, },
{ {
title: '创建人', title: '创建人',
key: 'teacherName', key: 'createName',
dataIndex: 'teacherName' dataIndex: 'createName'
},
{
title: <span>
<span>店铺展示</span>
<Tooltip title="开启后,用户可在店铺内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”店铺展示。关闭后,店铺内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。"><i className="icon iconfont" style={{ marginLeft: '5px',cursor:'pointer',color:'#bfbfbf'}}>&#xe61d;</i></Tooltip>
</span>,
width: "7%",
dataIndex: "courseware",
render: (val, item, index) => {
return (
<Switch defaultChecked={item.shelfState==="YES"?true:false} onChange={()=>this.changeShelfState(item)}/>
)
},
},
{
title: "观看用户数",
width: "10%",
key: "watchUserCount",
dataIndex: "watchUserCount",
render: (val, item) => {
return (
<div className="watchUserCount">{val}</div>
)
},
}, },
{ {
title: '创建时间', title: '创建时间',
key: 'createTime', key: 'created',
dataIndex: 'createTime', dataIndex: 'created',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val) return formatDate('YYYY-MM-DD H:i', val)
...@@ -88,8 +110,8 @@ class VideoCourseList extends React.Component { ...@@ -88,8 +110,8 @@ class VideoCourseList extends React.Component {
}, },
{ {
title: '更新时间', title: '更新时间',
key: 'updateTime', key: 'updated',
dataIndex: 'updateTime', dataIndex: 'updated',
sorter: true, sorter: true,
render: (val) => { render: (val) => {
return formatDate('YYYY-MM-DD H:i', val) return formatDate('YYYY-MM-DD H:i', val)
...@@ -102,19 +124,21 @@ class VideoCourseList extends React.Component { ...@@ -102,19 +124,21 @@ class VideoCourseList extends React.Component {
render: (val, record) => { render: (val, record) => {
return ( return (
<div className="operate"> <div className="operate">
<div className="operate__item" onClick={() => this.handleShowShareModal(record)}>分享</div> <div className="operate__item">观看数据</div>
<span className="operate__item split"> | </span> <span className="operate__item split"> | </span>
<div <div className="operate__item" onClick={() => this.handleShowShareModal(record)}>分享</div>
className="operate__item"
onClick={() => {
RCHistory.push(`/cloudclass/video_course/create?type=edit&id=${record.id}`);
}}
>编辑</div>
<span className="operate__item split"> | </span> <span className="operate__item split"> | </span>
<div <Dropdown overlay={this.renderMoreOperate(record)}>
className="operate__item" <span className="more-operate">
onClick={() => this.handleDeleteVideoCourse(record.id)} <span className="operate-text">更多</span>
>删除</div> <span
className="iconfont icon"
style={{ color: "#5289FA" }}
>
&#xe824;
</span>
</span>
</Dropdown>
</div> </div>
) )
} }
...@@ -123,6 +147,46 @@ class VideoCourseList extends React.Component { ...@@ -123,6 +147,46 @@ class VideoCourseList extends React.Component {
return columns; return columns;
} }
renderMoreOperate = (item) => {
return (
<div className="live-course-more-menu">
<div
className="operate__item"
onClick={() => {
RCHistory.push(`/create-video-course?type=edit&id=${item.id}`);
}}
>编辑</div>
<div
className="operate__item"
onClick={() => this.handleDeleteVideoCourse(item.id)}
>删除</div>
</div>
)
}
//改变上架状态
changeShelfState = (item) =>{
let _shelfState = item.shelfState
if(_shelfState==='NO'){
_shelfState = "YES";
item.shelfState = "YES"
}else{
_shelfState = "NO"
item.shelfState = "NO"
}
const params={
courseId: item.id,
shelfState:_shelfState
}
CourseService.changeVideoShelfState(params).then((res)=>{
if(res.success){
if(_shelfState === "YES"){
message.success("已开启展示");
}else{
message.success("已取消展示");
}
}
})
}
// 删除视频课 // 删除视频课
handleDeleteVideoCourse = (scheduleId) => { handleDeleteVideoCourse = (scheduleId) => {
Modal.confirm({ Modal.confirm({
...@@ -130,9 +194,13 @@ class VideoCourseList extends React.Component { ...@@ -130,9 +194,13 @@ class VideoCourseList extends React.Component {
content: '删除后,学员将不能进行观看。', content: '删除后,学员将不能进行观看。',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>, icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
onOk: () => { onOk: () => {
window.axios.Apollo('public/apollo/removeLessonSchedule', { const param ={
scheduleId courseId:scheduleId,
}).then(() => { storeId:User.getStoreId()
}
CourseService.delVideoSchedule(
param
).then(() => {
message.success('删除成功'); message.success('删除成功');
this.props.onChange(); this.props.onChange();
}) })
...@@ -170,13 +238,13 @@ class VideoCourseList extends React.Component { ...@@ -170,13 +238,13 @@ class VideoCourseList extends React.Component {
// 显示分享弹窗 // 显示分享弹窗
handleShowShareModal = (record, needStr = false) => { handleShowShareModal = (record, needStr = false) => {
const appId = CONFIG.appId[ENV]; // const appId = CONFIG.appId[ENV];
const shareUrl = CONFIG.shareUrl[ENV]; const shareUrl = "";
const { id, scheduleVideoUrl } = record; const { id, scheduleVideoUrl } = record;
const htmlUrl = `${LIVE_SHARE_MAP[ENV]}videoShare?id=${id}`; const htmlUrl = `${LIVE_SHARE_MAP[ENV]}videoShare?id=${id}`;
const link = `${appId}&redirect_uri=${encodeURIComponent(htmlUrl)}%26appid%3D${appId}&response_type=code&scope=snsapi_base&state=state#wechat_redirect`; const link = htmlUrl;
const longUrl = `${shareUrl}${link}`; const longUrl = "";
const { coverUrl, scheduleName } = record; const { coverUrl, scheduleName } = record;
const shareData = { const shareData = {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* @Author: 吴文洁 * @Author: 吴文洁
* @Date: 2020-04-29 10:26:32 * @Date: 2020-04-29 10:26:32
* @LastEditors: zhangleyuan * @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 15:20:14 * @LastEditTime: 2020-12-30 16:01:54
* @Description: 内容线路由配置 * @Description: 内容线路由配置
*/ */
import EmployeesManagePage from '@/modules/store-manage/EmployeesManagePage'; import EmployeesManagePage from '@/modules/store-manage/EmployeesManagePage';
......
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