Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
X
xiaomai-cloud-class-web
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
xiaomai-cloud-class
xiaomai-cloud-class-web
Commits
542a3ab6
Commit
542a3ab6
authored
Dec 30, 2020
by
zhangleyuan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:联调视屏课相关模块
parent
3695560d
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
160 additions
and
97 deletions
+160
-97
src/components/ImgCutModalNew.jsx
+5
-5
src/modules/course-manage/video-course/AddVideoCourse.jsx
+46
-51
src/modules/course-manage/video-course/components/VideoCourseList.jsx
+108
-40
src/routes/config/mainRoutes.tsx
+1
-1
No files found.
src/components/ImgCutModalNew.jsx
View file @
542a3ab6
...
...
@@ -30,10 +30,10 @@ class ImgCutModalNew extends React.Component {
const
fileName
=
window
.
random_string
(
16
)
+
name
.
slice
(
name
.
lastIndexOf
(
'.'
));
const
params
=
{
bizCode
:
bizCode
,
accessTypeEnum
:
'PUBLIC
'
,
instId
:
LS
.
get
(
'instId'
),
resourceName
:
fileN
ame
accessTypeEnum
:
"PUBLIC"
,
bizCode
:
'CLOUD_CLASS_COMMON
'
,
instId
:
User
.
getStoreId
(
),
resourceName
:
n
ame
}
// 压缩
if
(
compress
)
{
...
...
@@ -41,7 +41,7 @@ class ImgCutModalNew extends React.Component {
dataUrl
=
this
.
getBase64Size
(
dataUrl
)
>
compressSizeByte
?
await
this
.
handleCompressImg
(
dataUrl
,
compressSizeByte
,
cutWidth
)
:
dataUrl
;
}
const
cutImage
=
this
.
convertBase64UrlToBlob
(
dataUrl
);
Service
.
Hades
(
'public/hades/commonOssAuthority'
,
param
).
then
((
res
)
=>
{
Service
.
Hades
(
'public/hades/commonOssAuthority'
,
param
s
).
then
((
res
)
=>
{
const
{
resourceId
,
accessId
,
policy
,
callback
,
signature
,
key
,
host
}
=
res
.
result
;
const
localUrl
=
URL
.
createObjectURL
(
cutImage
);
// 构建上传的表单
...
...
src/modules/course-manage/video-course/AddVideoCourse.jsx
View file @
542a3ab6
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-
28 10:12:44
* @LastEditTime: 2020-12-
30 17:20:19
* @Description: 视频课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -20,6 +20,7 @@ import SelectStudent from '../modal/select-student';
import
SelectPrepareFileModal
from
'../../prepare-lesson/modal/SelectPrepareFileModal'
;
import
PreviewCourseModal
from
'../modal/PreviewCourseModal'
;
import
StoreService
from
"@/domains/store-domain/storeService"
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
User
from
'@/common/js/user'
;
import
'./AddVideoCourse.less'
;
...
...
@@ -43,13 +44,13 @@ class AddVideoCourse extends React.Component {
scheduleVideoId
:
null
,
// 视频课链接
coverId
:
null
,
// 视频封面的recourceId
coverUrl
:
null
,
// 视频课封面
joinType
:
null
,
// 观看模式, 默认为指定某些学员可以观看
studentList
:
[],
// 上课学员列表
shelfState
:
'YES'
,
//是否开启店铺展示
scheduleMedia
:
[{
// 视频课媒体资源
contentType
:
"INTRO"
,
mediaType
:
'TEXT'
,
mediaContent
:
''
,
key
:
EDIT_BOX_KEY
key
:
Math
.
random
()
}],
diskList
:
[],
// 机构可见磁盘目录
selectedFileList
:
[],
// 已经从资料云盘中勾选的文件
...
...
@@ -69,12 +70,12 @@ class AddVideoCourse extends React.Component {
this
.
getCourseCatalogList
();
if
(
pageType
===
'edit'
)
{
this
.
handleFetchScheudleDetail
(
id
);
this
.
handleFetchStudentList
(
id
);
//
this.handleFetchStudentList(id);
}
}
//获取分类列表
getCourseCatalogList
=
()
=>
{
StoreService
.
getCourseCatalogList
({
current
:
1
,
size
:
10
}).
then
((
res
)
=>
{
StoreService
.
getCourseCatalogList
({
current
:
1
,
size
:
10
00
}).
then
((
res
)
=>
{
this
.
setState
({
courseCatalogList
:
res
.
result
.
records
})
...
...
@@ -96,9 +97,9 @@ class AddVideoCourse extends React.Component {
}
}
// 获取视频课详情
handleFetchScheudleDetail
=
(
schedul
eId
)
=>
{
window
.
axios
.
Apollo
(
'public/apollo/getLessonScheduleDetail'
,
{
schedul
eId
handleFetchScheudleDetail
=
(
cours
eId
)
=>
{
CourseService
.
videoScheduleDetail
(
{
cours
eId
}).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
||
{};
const
{
...
...
@@ -107,11 +108,9 @@ class AddVideoCourse extends React.Component {
videoType
,
videoDuration
,
videoName
,
studentIds
,
scheduleMedia
,
courseName
,
scheduleVideoId
,
joinType
,
scheduleVideoUrl
,
}
=
result
;
this
.
setState
({
...
...
@@ -120,11 +119,9 @@ class AddVideoCourse extends React.Component {
videoType
,
videoName
,
videoDuration
,
studentIds
,
scheduleMedia
,
courseName
,
scheduleVideoId
,
joinType
,
scheduleVideoUrl
,
});
...
...
@@ -132,19 +129,19 @@ class AddVideoCourse extends React.Component {
}
// 获取视频课学员
handleFetchStudentList
=
(
scheduleId
)
=>
{
window
.
axios
.
Apollo
(
'public/apollo/getLessonStuIdListByScheduleId'
,
{
scheduleId
}).
then
((
res
)
=>
{
const
studentIds
=
res
.
result
||
[];
const
studentList
=
[];
_
.
each
(
studentIds
,
(
item
)
=>
{
studentList
.
push
({
studentId
:
item
});
});
//
handleFetchStudentList = (scheduleId) => {
//
window.axios.Apollo('public/apollo/getLessonStuIdListByScheduleId', {
//
scheduleId
//
}).then((res) => {
//
const studentIds = res.result || [];
//
const studentList = [];
//
_.each(studentIds, (item) => {
//
studentList.push({ studentId: item });
//
});
this
.
setState
({
studentList
})
});
}
//
this.setState({ studentList })
//
});
//
}
// 获取机构可见的磁盘
// handleFetchDiskList = () => {
...
...
@@ -317,29 +314,22 @@ class AddVideoCourse extends React.Component {
storeId
:
User
.
getStoreId
(),
shelfState
,
whetherVisitorsJoin
};
// 校验必填字段:课程名称, 课程视频
this
.
handleValidate
(
courseName
,
scheduleVideoId
,
joinType
,
scheduleMedia
).
then
((
res
)
=>
{
this
.
handleValidate
(
courseName
,
scheduleVideoId
,
categoryId
,
scheduleMedia
).
then
((
res
)
=>
{
if
(
!
res
)
return
;
if
(
pageType
===
'add'
)
{
window
.
axios
.
Apollo
(
'public/apollo/createLessonSchedule'
,
commonParams
).
then
((
res
)
=>
{
CourseService
.
createVideoSchedule
(
commonParams
).
then
((
res
)
=>
{
if
(
!
res
)
return
;
message
.
success
(
"新建成功"
);
// localStorage.setItem('videoCourseItem', JSON.stringify({
// ...commonParams,
// coverUrl,
// scheduleVideoUrl,
// id: res.result
// }));
window
.
RCHistory
.
goBack
();
})
}
else
{
const
editParams
=
{
id
,
courseId
:
id
,
...
commonParams
,
}
window
.
axios
.
Apollo
(
'public/apollo/editLessonSchedule'
,
editParams
).
then
((
res
)
=>
{
CourseService
.
editVideoSchedule
(
editParams
).
then
((
res
)
=>
{
if
(
!
res
)
return
;
message
.
success
(
"保存成功"
);
window
.
RCHistory
.
goBack
();
...
...
@@ -348,24 +338,29 @@ class AddVideoCourse extends React.Component {
});
}
handleValidate
=
(
courseName
,
scheduleVideoId
,
joinType
,
scheduleMedia
)
=>
{
handleValidate
=
(
courseName
,
scheduleVideoId
,
categoryId
,
scheduleMedia
)
=>
{
return
new
Promise
((
resolve
)
=>
{
if
(
!
courseName
)
{
message
.
warning
(
'请输入课程名称'
);
resolve
(
false
);
}
else
if
(
!
scheduleVideoId
)
{
return
false
}
if
(
!
scheduleVideoId
)
{
message
.
warning
(
'请上传视频'
);
resolve
(
false
);
}
else
if
(
!
joinType
)
{
message
.
warning
(
'请选择观看设置'
);
return
false
}
if
(
!
categoryId
){
message
.
warning
(
'请选择课程分类'
);
resolve
(
false
);
}
else
{
const
textMedia
=
scheduleMedia
.
filter
((
item
)
=>
item
.
mediaType
===
'TEXT'
);
for
(
let
i
=
0
,
len
=
textMedia
.
length
;
i
<
len
;
i
++
)
{
if
(
textMedia
[
i
].
mediaContentLength
&&
textMedia
[
i
].
mediaContentLength
.
length
>
1000
)
{
message
.
warning
(
`第
${
i
+
1
}
个文字简介的字数超过了1000个字`
);
resolve
(
false
);
}
return
false
}
const
textMedia
=
scheduleMedia
.
filter
((
item
)
=>
item
.
mediaType
===
'TEXT'
);
for
(
let
i
=
0
,
len
=
textMedia
.
length
;
i
<
len
;
i
++
)
{
if
(
textMedia
[
i
].
mediaContentLength
&&
textMedia
[
i
].
mediaContentLength
.
length
>
1000
)
{
message
.
warning
(
`第
${
i
+
1
}
个文字简介的字数超过了1000个字`
);
resolve
(
false
);
return
false
}
}
resolve
(
true
);
...
...
@@ -471,12 +466,12 @@ class AddVideoCourse extends React.Component {
</
div
>
<
div
className=
"course-catalog"
>
<
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="请选择课程分类" />
}
{
(
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
className=
"intro-info mt16"
>
<
AddVideoIntro
...
...
src/modules/course-manage/video-course/components/VideoCourseList.jsx
View file @
542a3ab6
...
...
@@ -2,18 +2,20 @@
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-
26 14:10:44
* @LastEditTime: 2020-12-
30 17:44:18
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Table
,
Modal
,
message
}
from
'antd'
;
import
{
Table
,
Modal
,
message
,
Tooltip
,
Switch
,
Dropdown
}
from
'antd'
;
import
{
PageControl
}
from
"@/components"
;
import
{
LIVE_SHARE_MAP
}
from
'@/common/constants/academic/cloudClass'
;
import
StudentListModal
from
'../modal/StudentListModal'
;
import
ShareLiveModal
from
'@/modules/course-manage/modal/ShareLiveModal'
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
User
from
'@/common/js/user'
import
'./VideoCourseList.less'
;
...
...
@@ -44,43 +46,63 @@ class VideoCourseList extends React.Component {
title
:
'视频课'
,
key
:
'scheduleName'
,
dataIndex
:
'scheduleName'
,
width
:
'2
5
%'
,
width
:
'2
0
%'
,
render
:
(
val
,
record
)
=>
{
const
{
coverUrl
,
scheduleVideoUrl
}
=
record
;
return
(
<
div
className=
"record__item"
>
{
/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */
}
<
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
>
)
}
},
{
title
:
'
学员人数
'
,
key
:
"stuNum"
,
dataIndex
:
"stuNum"
,
title
:
'
课程分类
'
,
key
:
'categoryName'
,
dataIndex
:
'categoryName'
,
render
:
(
val
,
record
)
=>
{
return
(
<
span
className=
"operate-text"
onClick=
{
()
=>
this
.
handleShowStudentListModal
(
record
)
}
>
{
val
}
</
span
>
);
},
<
div
className=
"record__item"
>
{
record
.
categoryName
}
</
div
>
)
}
},
{
title
:
'创建人'
,
key
:
'teacherName'
,
dataIndex
:
'teacherName'
key
:
'createName'
,
dataIndex
:
'createName'
},
{
title
:
<
span
>
<
span
>
店铺展示
</
span
>
<
Tooltip
title=
"开启后,用户可在店铺内查看到此课程。若课程“未成功开课”,则系统会自动“关闭”店铺展示。关闭后,店铺内不再展示此课程,但用户仍可通过分享的海报/链接查看此课程。"
><
i
className=
"icon iconfont"
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
}
}
>

</
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
:
'创建时间'
,
key
:
'create
Time
'
,
dataIndex
:
'create
Time
'
,
key
:
'create
d
'
,
dataIndex
:
'create
d
'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
...
...
@@ -88,8 +110,8 @@ class VideoCourseList extends React.Component {
},
{
title
:
'更新时间'
,
key
:
'update
Time
'
,
dataIndex
:
'update
Time
'
,
key
:
'update
d
'
,
dataIndex
:
'update
d
'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
...
...
@@ -102,19 +124,21 @@ class VideoCourseList extends React.Component {
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
"operate"
>
<
div
className=
"operate__item"
onClick=
{
()
=>
this
.
handleShowShareModal
(
record
)
}
>
分享
</
div
>
<
div
className=
"operate__item"
>
观看数据
</
div
>
<
span
className=
"operate__item split"
>
|
</
span
>
<
div
className=
"operate__item"
onClick=
{
()
=>
{
RCHistory
.
push
(
`/cloudclass/video_course/create?type=edit&id=${record.id}`
);
}
}
>
编辑
</
div
>
<
div
className=
"operate__item"
onClick=
{
()
=>
this
.
handleShowShareModal
(
record
)
}
>
分享
</
div
>
<
span
className=
"operate__item split"
>
|
</
span
>
<
div
className=
"operate__item"
onClick=
{
()
=>
this
.
handleDeleteVideoCourse
(
record
.
id
)
}
>
删除
</
div
>
<
Dropdown
overlay=
{
this
.
renderMoreOperate
(
record
)
}
>
<
span
className=
"more-operate"
>
<
span
className=
"operate-text"
>
更多
</
span
>
<
span
className=
"iconfont icon"
style=
{
{
color
:
"#5289FA"
}
}
>

</
span
>
</
span
>
</
Dropdown
>
</
div
>
)
}
...
...
@@ -123,6 +147,46 @@ class VideoCourseList extends React.Component {
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
)
=>
{
Modal
.
confirm
({
...
...
@@ -130,9 +194,13 @@ class VideoCourseList extends React.Component {
content
:
'删除后,学员将不能进行观看。'
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
onOk
:
()
=>
{
window
.
axios
.
Apollo
(
'public/apollo/removeLessonSchedule'
,
{
scheduleId
}).
then
(()
=>
{
const
param
=
{
courseId
:
scheduleId
,
storeId
:
User
.
getStoreId
()
}
CourseService
.
delVideoSchedule
(
param
).
then
(()
=>
{
message
.
success
(
'删除成功'
);
this
.
props
.
onChange
();
})
...
...
@@ -170,13 +238,13 @@ class VideoCourseList extends React.Component {
// 显示分享弹窗
handleShowShareModal
=
(
record
,
needStr
=
false
)
=>
{
const
appId
=
CONFIG
.
appId
[
ENV
];
const
shareUrl
=
CONFIG
.
shareUrl
[
ENV
]
;
//
const appId = CONFIG.appId[ENV];
const
shareUrl
=
""
;
const
{
id
,
scheduleVideoUrl
}
=
record
;
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
longUrl
=
`
${
shareUrl
}${
link
}
`
;
const
link
=
htmlUrl
;
const
longUrl
=
""
;
const
{
coverUrl
,
scheduleName
}
=
record
;
const
shareData
=
{
...
...
src/routes/config/mainRoutes.tsx
View file @
542a3ab6
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-04-29 10:26:32
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-
25 15:20:1
4
* @LastEditTime: 2020-12-
30 16:01:5
4
* @Description: 内容线路由配置
*/
import
EmployeesManagePage
from
'@/modules/store-manage/EmployeesManagePage'
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment