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
fdf7e07d
Commit
fdf7e07d
authored
Dec 25, 2020
by
zhangleyuan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:增加视频课模块
parent
93970161
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
1725 additions
and
230 deletions
+1725
-230
src/modules/course-manage/video-course/AddVideoCourse.jsx
+562
-0
src/modules/course-manage/video-course/AddVideoCourse.less
+137
-0
src/modules/course-manage/video-course/components/VideoCourseFilter.jsx
+142
-0
src/modules/course-manage/video-course/components/VideoCourseFilter.less
+21
-0
src/modules/course-manage/video-course/components/VideoCourseList.jsx
+260
-0
src/modules/course-manage/video-course/components/VideoCourseList.less
+54
-0
src/modules/course-manage/video-course/components/VideoCourseOpt.less
+8
-0
src/modules/course-manage/video-course/components/VieoCourseOpt.jsx
+34
-0
src/modules/course-manage/video-course/index.jsx
+86
-0
src/modules/course-manage/video-course/modal/StudentListModal.jsx
+378
-0
src/modules/course-manage/video-course/modal/StudentListModal.less
+21
-0
src/modules/store-manege/StoreDecorationPage.tsx
+0
-221
src/routes/config/mainRoutes.tsx
+17
-4
src/routes/config/menuList.tsx
+5
-5
No files found.
src/modules/course-manage/video-course/AddVideoCourse.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:07:47
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 15:26:06
* @Description: 视频课新增/编辑页
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Button
,
Input
,
Radio
,
message
,
Modal
}
from
'antd'
;
import
{
DISK_MAP
,
FileTypeIcon
,
FileVerifyMap
}
from
'@/common/constants/academic/lessonEnum'
;
import
{
ImgCutModalNew
}
from
'@/components'
;
import
ShowTips
from
"@/components/ShowTips"
;
import
Breadcrumbs
from
"@/components/Breadcrumbs"
;
import
AddLiveIntro
from
'../components/AddLiveIntro'
;
import
SelectStudent
from
'../modal/select-student'
;
import
SelectPrepareFileModal
from
'../../prepare-lesson/modal/SelectPrepareFileModal'
;
import
PreviewCourseModal
from
'../modal/PreviewCourseModal'
;
import
'./AddVideoCourse.less'
;
const
EDIT_BOX_KEY
=
Math
.
random
(
16
);
class
AddVideoCourse
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
const
id
=
getParameterByName
(
"id"
);
const
pageType
=
getParameterByName
(
"type"
);
this
.
state
=
{
id
,
// 视频课ID,编辑的时候从URL上带过来
pageType
,
// 页面类型: add->新建 edit->编辑
imageFile
:
null
,
// 需要被截取的图片
scheduleName
:
null
,
// 视频课名称
scheduleVideoId
:
null
,
// 视频课链接
coverId
:
null
,
// 视频封面的recourceId
coverUrl
:
null
,
// 视频课封面
joinType
:
null
,
// 观看模式, 默认为指定某些学员可以观看
studentList
:
[],
// 上课学员列表
scheduleMedia
:
[{
// 视频课媒体资源
mediaType
:
'TEXT'
,
mediaContent
:
''
,
key
:
EDIT_BOX_KEY
}],
diskList
:
[],
// 机构可见磁盘目录
selectedFileList
:
[],
// 已经从资料云盘中勾选的文件
showCutModal
:
false
,
// 是否显示截图弹窗
showSelectFileModal
:
false
,
studentModal
:
false
,
}
}
componentWillMount
()
{
// this.handleFetchDiskList();
const
{
id
,
pageType
}
=
this
.
state
;
if
(
pageType
===
'edit'
)
{
this
.
handleFetchScheudleDetail
(
id
);
this
.
handleFetchStudentList
(
id
);
}
}
// 获取视频课详情
handleFetchScheudleDetail
=
(
scheduleId
)
=>
{
window
.
axios
.
Apollo
(
'public/apollo/getLessonScheduleDetail'
,
{
scheduleId
}).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
||
{};
const
{
coverId
,
coverUrl
,
videoType
,
videoDuration
,
videoName
,
studentIds
,
scheduleMedia
,
scheduleName
,
scheduleVideoId
,
joinType
,
scheduleVideoUrl
,
}
=
result
;
this
.
setState
({
coverId
,
coverUrl
,
videoType
,
videoName
,
videoDuration
,
studentIds
,
scheduleMedia
,
scheduleName
,
scheduleVideoId
,
joinType
,
scheduleVideoUrl
,
});
})
}
// 获取视频课学员
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
})
});
}
// 获取机构可见的磁盘
// handleFetchDiskList = () => {
// axios.Apollo('public/apollo/getUserDisk', {}).then((res) => {
// const { result = [] } = res;
// const diskList = result.map((item) => {
// return {
// ...item,
// folderName: DISK_MAP[item.disk]
// }
// });
// this.setState({ diskList });
// });
// }
handleGoBack
=
()
=>
{
Modal
.
confirm
({
title
:
'确认要返回吗?'
,
content
:
'返回后,本次编辑的内容将不被保存。'
,
okText
:
'确认返回'
,
cancelText
:
'留在本页'
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
onOk
:
()
=>
{
RCHistory
.
goBack
();
}
});
}
// 修改表单
handleChangeForm
=
(
field
,
value
,
coverUrl
)
=>
{
this
.
setState
({
[
field
]:
value
,
coverUrl
:
coverUrl
?
coverUrl
:
this
.
state
.
coverUrl
});
}
// 显示选择学员弹窗
handleShowSelectStuModal
=
()
=>
{
this
.
setState
({
studentModal
:
true
});
const
{
studentList
,
selectedStuList
}
=
this
.
state
;
// const _studentList = _.map(studentList, (item) => {
// return item.studentId
// })
const
studentModal
=
(
<
SelectStudent
showTabs=
{
true
}
type=
"videoCourse"
onSelect=
{
this
.
handleSelectStudent
}
after=
{
true
}
//表明是不是上课后的状态
studentList=
{
studentList
}
close=
{
()
=>
{
this
.
setState
({
studentModal
:
null
,
});
}
}
/>
)
this
.
setState
({
studentModal
});
}
handleSelectStudent
=
(
studentIds
)
=>
{
let
studentList
=
[];
_
.
each
(
studentIds
,
(
item
)
=>
{
studentList
.
push
({
studentId
:
item
});
});
// this.setState({ studentModal: null });
this
.
setState
({
studentList
});
this
.
setState
({
studentModal
:
false
});
}
// 显示预览弹窗
handleShowPreviewModal
=
()
=>
{
const
{
coverUrl
,
scheduleVideoUrl
,
scheduleName
,
scheduleMedia
}
=
this
.
state
;
const
courseBasinInfo
=
{
coverUrl
,
scheduleVideoUrl
,
courseName
:
scheduleName
,
}
const
courseIntroInfo
=
{
liveCourseMediaRequests
:
scheduleMedia
}
const
previewCourseModal
=
(
<
PreviewCourseModal
type=
"videoCourse"
courseBasinInfo=
{
courseBasinInfo
}
courseIntroInfo=
{
courseIntroInfo
}
close=
{
()
=>
{
this
.
setState
({
previewCourseModal
:
null
})
}
}
/>
);
this
.
setState
({
previewCourseModal
});
}
// 选择视频
handleSelectVideo
=
(
file
)
=>
{
this
.
setState
({
showSelectFileModal
:
false
})
const
{
ossUrl
,
resourceId
,
folderName
,
folderFormat
,
folderSize
}
=
file
;
const
videoDom
=
document
.
createElement
(
'video'
);
videoDom
.
src
=
ossUrl
;
videoDom
.
onloadedmetadata
=
()
=>
{
this
.
setState
({
size
:
folderSize
,
videoName
:
folderName
,
videoType
:
folderFormat
,
scheduleVideoUrl
:
ossUrl
,
scheduleVideoId
:
resourceId
,
videoDuration
:
videoDom
.
duration
});
}
}
// 上传封面图
handleShowImgCutModal
=
(
event
)
=>
{
const
imageFile
=
event
.
target
.
files
[
0
];
if
(
!
imageFile
)
return
;
this
.
setState
({
imageFile
,
showCutModal
:
true
,
});
}
// 保存
handleSubmit
=
()
=>
{
const
{
instId
,
adminId
}
=
window
.
currentUserInstInfo
;
const
{
id
,
size
,
coverId
,
coverUrl
,
pageType
,
joinType
,
videoName
,
videoDuration
,
studentList
,
scheduleName
,
scheduleMedia
,
scheduleVideoId
,
scheduleVideoUrl
,
}
=
this
.
state
;
const
commonParams
=
{
size
,
instId
,
coverId
,
videoName
,
videoDuration
,
scheduleName
,
scheduleVideoId
,
joinType
,
teacherId
:
adminId
,
studentIds
:
_
.
pluck
(
studentList
,
"studentId"
),
scheduleMedia
:
scheduleMedia
.
filter
(
item
=>
!!
item
.
mediaContent
),
};
// 校验必填字段:课程名称, 课程视频
this
.
handleValidate
(
scheduleName
,
scheduleVideoId
,
joinType
,
scheduleMedia
).
then
((
res
)
=>
{
if
(
!
res
)
return
;
if
(
pageType
===
'add'
)
{
window
.
axios
.
Apollo
(
'public/apollo/createLessonSchedule'
,
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
,
...
commonParams
,
}
window
.
axios
.
Apollo
(
'public/apollo/editLessonSchedule'
,
editParams
).
then
((
res
)
=>
{
if
(
!
res
)
return
;
message
.
success
(
"保存成功"
);
window
.
RCHistory
.
goBack
();
});
}
});
}
handleValidate
=
(
scheduleName
,
scheduleVideoId
,
joinType
,
scheduleMedia
)
=>
{
return
new
Promise
((
resolve
)
=>
{
if
(
!
scheduleName
)
{
message
.
warning
(
'请输入课程名称'
);
resolve
(
false
);
}
else
if
(
!
scheduleVideoId
)
{
message
.
warning
(
'请上传视频'
);
resolve
(
false
);
}
else
if
(
!
joinType
)
{
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
);
}
}
}
resolve
(
true
);
});
}
render
()
{
const
{
pageType
,
scheduleName
,
scheduleVideoId
,
coverId
,
coverUrl
,
scheduleVideoUrl
,
studentList
,
scheduleMedia
,
showCutModal
,
showSelectFileModal
,
diskList
,
imageFile
,
joinType
,
videoName
,
videoType
,
studentModal
}
=
this
.
state
;
// 已选择的上课学员数量
const
hasSelectedStu
=
studentList
.
length
;
const
courseWareIcon
=
FileVerifyMap
[
videoType
]
?
FileTypeIcon
[
FileVerifyMap
[
videoType
].
type
]
:
FileTypeIcon
[
videoType
];
return
(
<
div
className=
"page add-video-course-page"
>
<
Breadcrumbs
navList=
{
pageType
===
"add"
?
"新建视频课"
:
"编辑视频课"
}
goBack=
{
this
.
handleGoBack
}
/>
<
div
className=
"box"
>
<
div
className=
"show-tips"
>
<
ShowTips
message=
"请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦助教保有依据国家规定及平台规则进行处理的权利"
/>
</
div
>
<
div
className=
"form"
>
<
div
className=
"course-name required"
>
<
span
className=
"label"
>
课程名称:
</
span
>
<
Input
value=
{
scheduleName
}
placeholder=
"请输入视频课的名称(40字以内)"
maxLength=
{
40
}
style=
{
{
width
:
240
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangeForm
(
'scheduleName'
,
e
.
target
.
value
)}
}
/>
</
div
>
<
div
className=
"upload-video mt16"
>
<
div
className=
"content flex"
>
<
span
className=
"label required"
>
视频上传:
</
span
>
<
div
className=
"value"
>
{
scheduleVideoId
?
<
div
className=
"course-ware"
>
<
img
className=
"course-ware__img"
src=
{
courseWareIcon
}
/>
<
span
className=
"course-ware__name"
>
{
videoName
}
</
span
>
</
div
>
:
<
div
className=
"course-ware--empty"
>
从资料云盘中选择视频
</
div
>
}
</
div
>
</
div
>
<
div
className=
"sub-content"
>
<
Button
type=
"primary"
onClick=
{
()
=>
{
this
.
setState
({
showSelectFileModal
:
true
})
}
}
>
{
`${(pageType === 'add' && !scheduleVideoId) ? '选择' : '更换'}视频`
}
</
Button
>
<
span
className=
"tips"
>
视频数量限制1个,大小不超过500M
</
span
>
</
div
>
</
div
>
<
div
className=
"cover-url flex mt16"
>
<
div
className=
"label"
>
视频封面:
</
div
>
<
div
className=
"cover-url__wrap"
>
<
div
className=
"img-content"
>
{
/* 如果视频和封面都没有上传的话, 那么就显示缺省, 如果上传了视频, 那么封面图就默认显示视频的第一帧, 如果上传了封面图, 那么就显示上传的封面图 */
}
{
(
scheduleVideoUrl
||
coverUrl
)?
<
img
src=
{
coverUrl
||
`${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
:
<
div
className=
"empty-img"
>
若不上传
<
br
/>
系统默认将视频首帧作为封面图
</
div
>
}
</
div
>
<
div
className=
"opt-btns"
>
<
input
type=
"file"
accept=
"image/png, image/jpeg, image/jpg"
ref=
"picInputFile"
style=
{
{
display
:
'none'
}
}
onChange=
{
(
event
)
=>
{
this
.
handleShowImgCutModal
(
event
)
}
}
/>
<
Button
onClick=
{
()
=>
{
this
.
setState
({
currentInputFile
:
this
.
refs
.
picInputFile
});
this
.
refs
.
picInputFile
.
click
()
}
}
>
{
`${(pageType === 'add' && (!scheduleVideoId && !coverUrl)) ? '上传' : '修改'}封面`
}
</
Button
>
<
div
className=
"tips"
>
建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。
</
div
>
</
div
>
</
div
>
</
div
>
<
div
className=
"watch-setting flex mt16"
>
<
div
className=
"label required"
>
分享设置:
</
div
>
<
div
className=
"content"
>
<
Radio
.
Group
onChange=
{
(
e
)
=>
this
.
handleChangeForm
(
'joinType'
,
e
.
target
.
value
)
}
value=
{
joinType
}
>
<
Radio
value=
{
'ALL'
}
>
<
div
className=
"radio-item"
>
<
div
className=
"text mr16"
>
允许任何学员通过视频课链接加入学习
</
div
>
<
div
className=
"sub-text"
>
加入后,在读学员可通过家长端和视频课链接观看,非在读学员仅可通过视频课链接观看
</
div
>
</
div
>
</
Radio
>
<
Radio
value=
{
'NORMAL'
}
>
<
div
className=
"radio-item"
>
<
div
className=
"text mr16"
>
仅在读学员可通过视频课链接加入学习
</
div
>
<
div
className=
"sub-text"
>
加入后,在读学员可通过家长端和视频课链接观看
</
div
>
</
div
>
</
Radio
>
<
Radio
value=
{
'ASSIGN'
}
>
<
div
className=
"radio-item mb0"
>
<
div
className=
"text mr16"
>
仅指定学员可通过视频课链接加入学习
</
div
>
<
div
className=
"sub-text"
>
加入后,在读学员可通过家长端和视频课链接观看,非在读学员仅可通过视频课链接观看
</
div
>
</
div
>
</
Radio
>
</
Radio
.
Group
>
{
// 当观看模式为指定学员时,显示选择学员的入口
joinType
===
'ASSIGN'
&&
<
div
className=
"select-student flex"
>
<
Button
onClick=
{
this
.
handleShowSelectStuModal
}
>
选择学员
</
Button
>
<
div
className=
"has-selected"
>
已选择
<
span
style=
{
{
color
:
"#FF8534"
}
}
>
{
hasSelectedStu
}
</
span
>
名学员
</
div
>
</
div
>
}
</
div
>
</
div
>
<
div
className=
"intro-info mt16"
>
<
AddLiveIntro
data=
{
{
liveCourseMediaRequests
:
scheduleMedia
,
label
:
'视频课简介'
}
}
onChange=
{
this
.
handleChangeForm
}
/>
</
div
>
</
div
>
</
div
>
<
div
className=
"footer"
>
<
Button
onClick=
{
this
.
handleGoBack
}
>
取消
</
Button
>
<
Button
onClick=
{
this
.
handleShowPreviewModal
}
>
预览
</
Button
>
<
Button
type=
"primary"
onClick=
{
_
.
debounce
(()
=>
this
.
handleSubmit
(),
3000
,
true
)
}
>
保存
</
Button
>
</
div
>
{
/* 选择备课文件弹窗 */
}
<
SelectPrepareFileModal
operateType=
"select"
selectTypeList=
{
[
'MP4'
]
}
accept=
"video/mp4"
confirm=
{
{
title
:
'文件过大,无法上传'
,
content
:
'为保障学员的观看体验,上传的视频大小不能超过500M'
,
}
}
tooltip=
{
'格式支持mp4,大小不超过500M'
}
isOpen=
{
showSelectFileModal
}
diskList=
{
diskList
}
addVideo=
{
true
}
onClose=
{
()
=>
{
this
.
setState
({
showSelectFileModal
:
false
})
}
}
onSelect=
{
this
.
handleSelectVideo
}
/>
<
ImgCutModalNew
title=
"裁剪"
width=
{
550
}
cutWidth=
{
500
}
cutHeight=
{
282
}
cutContentWidth=
{
500
}
cutContentHeight=
{
300
}
visible=
{
showCutModal
}
imageFile=
{
imageFile
}
bizCode=
'LIVE_COURSE_MEDIA'
onOk=
{
(
urlStr
,
resourceId
)
=>
{
this
.
setState
({
showCutModal
:
false
});
this
.
handleChangeForm
(
'coverId'
,
resourceId
,
urlStr
)
this
.
state
.
currentInputFile
.
value
=
''
;
}
}
onClose=
{
()
=>
this
.
setState
({
showCutModal
:
false
})
}
reUpload=
{
()
=>
{
this
.
state
.
currentInputFile
.
click
()
}
}
/>
{
/* {
<SelectStudent
addVideo={'addVideo'}
studentModal={studentModal}
showTabs={true}
type="videoCourse"
onSelect={this.handleSelectStudent}
after={true} //表明是不是上课后的状态
savedList={studentList}
close={() => {
this.setState({
// studentModal: null,
studentModal: false,
});
}}
/>
} */
}
{
this
.
state
.
studentModal
}
{
this
.
state
.
previewCourseModal
}
</
div
>
)
}
}
export
default
AddVideoCourse
;
src/modules/course-manage/video-course/AddVideoCourse.less
0 → 100644
View file @
fdf7e07d
.add-video-course-page {
.ant-radio-group {
display: flex;
flex-direction: column;
.radio-item {
margin-bottom: 12px;
.text {
color: #333;
}
.sub-text {
color: #999;
}
}
.ant-radio {
vertical-align: top;
padding-top: 2px;
}
}
.form {
margin-top: 16px;
padding: 0 16px;
.required {
position: relative;
&::before {
position: absolute;
content: '*';
color: red;
left: -10px;
top: 6px;
}
&.label::before {
top: 0;
}
}
.course-ware {
display: flex;
align-items: center;
margin-bottom: 4px;
&__img {
width: 24px;
margin-right: 4px;
}
&__name {
color: #333;
}
}
.flex {
display: flex;
}
.cover-url__wrap {
.img-content {
width: 298px;
height: 172px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.empty-img {
width: 298px;
height: 172px;
border: 1px dashed #EBEBEB;
border-radius: 4px;
padding: 12px;
color: #999;
padding: 52px 24px;
text-align: center;
}
.opt-btns {
margin-top: 8px;
display: flex;
align-items: center;
.tips {
margin-left: 12px;
color: #999;
}
}
}
.select-student {
align-items: center;
margin-left: 24px;
margin-top: 8px;
.has-selected {
margin-left: 12px;
color: #333;
}
}
.sub-content {
margin-left: 70px;
margin-top: 4px;
.tips {
margin-left: 16px;
color: #999;
}
}
}
.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
src/modules/course-manage/video-course/components/VideoCourseFilter.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:11:57
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 14:45:09
* @Description: 视频课-搜索模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Row
,
Input
,
Select
}
from
'antd'
;
import
RangePicker
from
"@/modules/common/DateRangePicker"
;
// import TeacherSelectV5 from '@/modules/classManage_V5/classDetail/TeacherSelectV5';
import
'./VideoCourseFilter.less'
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
const
DEFAULT_QUERY
=
{
scheduleName
:
null
,
// 课程名称
teacherId
:
null
,
// 创建人
beginTime
:
null
,
// 开始日期
endTime
:
null
,
// 结束日期
}
class
VideoCourseFilter
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
query
:
{
...
DEFAULT_QUERY
},
// 使用扩展运算符,避免浅拷贝
}
}
// 改变搜索条件
handleChangeQuery
=
(
field
,
value
)
=>
{
this
.
setState
({
query
:
{
...
this
.
state
.
query
,
[
field
]:
value
,
current
:
1
,
}
},
()
=>
{
if
(
field
===
'scheduleName'
)
return
;
this
.
props
.
onChange
(
this
.
state
.
query
)
});
}
handleChangeDates
=
(
dates
)
=>
{
const
query
=
_
.
clone
(
this
.
state
.
query
);
if
(
_
.
isEmpty
(
dates
))
{
delete
query
.
beginTime
;
delete
query
.
endTime
;
}
else
{
query
.
beginTime
=
dates
[
0
].
valueOf
();
query
.
endTime
=
dates
[
1
].
valueOf
();
}
this
.
setState
({
query
,
current
:
1
,
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
})
}
// 重置搜索条件
handleReset
=
()
=>
{
this
.
setState
({
query
:
DEFAULT_QUERY
,
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
})
}
render
()
{
const
{
query
:
{
scheduleName
,
operator
,
beginTime
,
endTime
,
teacherId
,
}
}
=
this
.
state
;
return
(
<
div
className=
"video-course-filter"
>
<
Row
type=
"flex"
justify=
"space-between"
align=
"top"
>
<
div
className=
"search-condition"
>
<
div
className=
"search-condition__item"
>
<
span
className=
"search-name"
>
视频课:
</
span
>
<
Search
value=
{
scheduleName
}
placeholder=
"搜索视频课名称"
onChange=
{
(
e
)
=>
{
this
.
handleChangeQuery
(
'scheduleName'
,
e
.
target
.
value
)}
}
onSearch=
{
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
)
}
}
style=
{
{
width
:
"calc(100% - 70px)"
}
}
/>
</
div
>
<
div
className=
"search-condition__item"
>
{
/* <TeacherSelectV5
ref="TeacherSelect"
showSearch={true}
allowClear={true}
style={{ width: "calc(100% - 70px)" }}
onSelect={(teacherId) => { this.handleChangeQuery('teacherId', teacherId)}}
placeholder='请选择创建人'
label='创建人'
defaultValue={teacherId}
/> */
}
</
div
>
<
div
className=
"search-condition__item"
>
<
span
className=
"search-date"
>
创建日期:
</
span
>
<
RangePicker
id=
"course_date_picker"
allowClear=
{
false
}
value=
{
beginTime
?
[
moment
(
beginTime
),
moment
(
endTime
)]
:
null
}
format=
{
"YYYY-MM-DD"
}
onChange=
{
(
dates
)
=>
{
this
.
handleChangeDates
(
dates
)
}
}
style=
{
{
width
:
"calc(100% - 70px)"
}
}
/>
</
div
>
</
div
>
<
span
className=
"icon iconfont"
onClick=
{
this
.
handleReset
}
>

</
span
>
</
Row
>
</
div
>
)
}
}
export
default
VideoCourseFilter
;
src/modules/course-manage/video-course/components/VideoCourseFilter.less
0 → 100644
View file @
fdf7e07d
.video-course-filter {
position: relative;
.search-condition {
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 30%;
margin-right: 3%;
}
}
.iconfont {
position: absolute;
right: 12px;
cursor: pointer;
}
}
\ No newline at end of file
src/modules/course-manage/video-course/components/VideoCourseList.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 14:54:53
* @Description: 视频课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Table
,
Modal
,
message
}
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
'./VideoCourseList.less'
;
const
ENV
=
process
.
env
.
DEPLOY_ENV
||
'dev'
;
class
VideoCourseList
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
id
:
''
,
// 视频课ID
studentIds
:[]
}
}
componentDidMount
()
{
const
videoCourseItem
=
localStorage
.
getItem
(
'videoCourseItem'
);
if
(
videoCourseItem
)
{
const
_videoCourseItem
=
JSON
.
parse
(
videoCourseItem
);
this
.
handleShowShareModal
(
_videoCourseItem
,
true
);
}
}
// 请求表头
parseColumns
=
()
=>
{
const
columns
=
[
{
title
:
'视频课'
,
key
:
'scheduleName'
,
dataIndex
:
'scheduleName'
,
width
:
'25%'
,
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
>
</
div
>
)
}
},
{
title
:
'学员人数'
,
key
:
"stuNum"
,
dataIndex
:
"stuNum"
,
render
:
(
val
,
record
)
=>
{
return
(
<
span
className=
"operate-text"
onClick=
{
()
=>
this
.
handleShowStudentListModal
(
record
)
}
>
{
val
}
</
span
>
);
},
},
{
title
:
'创建人'
,
key
:
'teacherName'
,
dataIndex
:
'teacherName'
},
{
title
:
'创建时间'
,
key
:
'createTime'
,
dataIndex
:
'createTime'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
},
{
title
:
'更新时间'
,
key
:
'updateTime'
,
dataIndex
:
'updateTime'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
"operate"
>
<
div
className=
"operate__item"
onClick=
{
()
=>
this
.
handleShowShareModal
(
record
)
}
>
分享
</
div
>
<
span
className=
"operate__item split"
>
|
</
span
>
<
div
className=
"operate__item"
onClick=
{
()
=>
{
RCHistory
.
push
(
`/cloudclass/video_course/create?type=edit&id=${record.id}`
);
}
}
>
编辑
</
div
>
<
span
className=
"operate__item split"
>
|
</
span
>
<
div
className=
"operate__item"
onClick=
{
()
=>
this
.
handleDeleteVideoCourse
(
record
.
id
)
}
>
删除
</
div
>
</
div
>
)
}
}
];
return
columns
;
}
// 删除视频课
handleDeleteVideoCourse
=
(
scheduleId
)
=>
{
Modal
.
confirm
({
title
:
'你确定要删除此视频课吗?'
,
content
:
'删除后,学员将不能进行观看。'
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
onOk
:
()
=>
{
window
.
axios
.
Apollo
(
'public/apollo/removeLessonSchedule'
,
{
scheduleId
}).
then
(()
=>
{
message
.
success
(
'删除成功'
);
this
.
props
.
onChange
();
})
}
});
}
// 学员人数弹窗
handleShowStudentListModal
=
(
record
)
=>
{
const
{
studentIds
=
[],
id
}
=
this
.
state
;
if
(
id
!==
record
.
id
)
{
this
.
setState
({
id
:
record
.
id
})
}
const
studentListModal
=
(
<
StudentListModal
type=
'videoCourseList'
close=
{
(
studentIds
)
=>
this
.
setState
({
studentListModal
:
null
,
studentIds
})
}
studentIds=
{
studentIds
}
data=
{
record
}
refresh=
{
()
=>
{
this
.
props
.
onChange
();
}
}
/>
);
this
.
setState
({
studentListModal
});
}
// 显示分享弹窗
handleShowShareModal
=
(
record
,
needStr
=
false
)
=>
{
const
appId
=
CONFIG
.
appId
[
ENV
];
const
shareUrl
=
CONFIG
.
shareUrl
[
ENV
];
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
{
coverUrl
,
scheduleName
}
=
record
;
const
shareData
=
{
longUrl
,
coverUrl
,
scheduleVideoUrl
,
courseName
:
scheduleName
,
};
const
shareLiveModal
=
(
<
ShareLiveModal
needStr=
{
needStr
}
data=
{
shareData
}
type=
"videoClass"
close=
{
()
=>
{
this
.
setState
({
shareLiveModal
:
null
});
localStorage
.
setItem
(
'videoCourseItem'
,
''
);
}
}
/>
);
this
.
setState
({
shareLiveModal
});
}
handleChangeTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
this
.
props
;
let
{
order
:
_order
}
=
query
;
// 按创建时间升序排序
if
(
columnKey
===
'createTime'
&&
order
===
'ascend'
)
{
_order
=
'CREATED_ASC'
;
}
// 按创建时间降序排序
if
(
columnKey
===
'createTime'
&&
order
===
'descend'
)
{
_order
=
'CREATED_DESC'
;
}
// 按更新时间升序排序
if
(
columnKey
===
'updateTime'
&&
order
===
'ascend'
)
{
_order
=
'UPDATED_ASC'
;
}
// 按更新时间降序排序
if
(
columnKey
===
'updateTime'
&&
order
===
'descend'
)
{
_order
=
'UPDATED_DESC'
;
}
const
_query
=
{
...
query
,
order
:
_order
};
this
.
props
.
onChange
(
_query
);
}
render
()
{
const
{
dataSource
=
[],
totalCount
,
query
}
=
this
.
props
;
const
{
current
,
size
}
=
query
;
return
(
<
div
className=
"video-course-list"
>
<
Table
rowKey=
{
record
=>
record
.
id
}
dataSource=
{
dataSource
}
columns=
{
this
.
parseColumns
()
}
onChange=
{
this
.
handleChangeTable
}
pagination=
{
false
}
/>
<
div
className=
"box-footer"
>
<
PageControl
current=
{
current
-
1
}
pageSize=
{
size
}
total=
{
totalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{...
query
,
current
:
page
+
1
};
this
.
props
.
onChange
(
_query
)
}
}
/>
</
div
>
{
this
.
state
.
shareLiveModal
}
{
this
.
state
.
studentListModal
}
</
div
>
)
}
}
export
default
VideoCourseList
;
src/modules/course-manage/video-course/components/VideoCourseList.less
0 → 100644
View file @
fdf7e07d
.video-course-list {
margin-top: 12px;
.operate-text {
color: #FF8534;
cursor: pointer;
}
.operate {
display: flex;
&__item {
color: #FF8534;
cursor: pointer;
&.split {
margin: 0 8px;
color: #BFBFBF;
}
}
}
.record__item {
display: flex;
.course-cover {
min-width: 97px;
max-width: 97px;
height: 50px;
border-radius: 2px;
margin-right: 8px;
background-color: #666;
}
.course-name {
color: #666;
}
}
}
.video-course-more-menu {
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
border-radius: 4px;
div {
line-height: 30px;
padding: 0 15px;
cursor: pointer;
&:hover {
background: #f3f6fa;
}
}
}
\ No newline at end of file
src/modules/course-manage/video-course/components/VideoCourseOpt.less
0 → 100644
View file @
fdf7e07d
.video-course-opt {
margin-top: 16px;
.link {
color: #FF8534;
}
}
\ No newline at end of file
src/modules/course-manage/video-course/components/VieoCourseOpt.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 15:25:32
* @Description: 视频课-操作模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Button
}
from
'antd'
;
import
'./VideoCourseOpt.less'
;
export
default
function
VideoCourseOpt
()
{
return
(
<
div
className=
"video-course-opt"
>
<
Button
type=
"primary"
onClick=
{
()
=>
{
RCHistory
.
push
(
'/create-video-course?type=add'
);
}
}
className=
"mr12"
>
新建视频课
</
Button
>
<
a
href=
"https://mp.weixin.qq.com/s/vTfGS8SeRzarrUnF9fkYbA"
className=
"link"
target=
"_blank"
>
什么是视频课?
</
a
>
</
div
>
);
}
src/modules/course-manage/video-course/index.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:08:06
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 15:06:21
* @Description: 云课堂-视频课入口页面
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
VideoCourseFilter
from
'./components/VideoCourseFilter'
;
import
VideoCourseOpt
from
'./components/VieoCourseOpt'
;
import
VideoCourseList
from
'./components/VideoCourseList'
;
class
VideoCourse
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
const
{
instId
}
=
window
.
currentUserInstInfo
;
this
.
state
=
{
query
:
{
instId
,
size
:
10
,
current
:
1
,
},
dataSource
:
[],
// 视频课列表
totalCount
:
0
,
// 视频课数据总条数
}
}
componentWillMount
()
{
// 获取视频课列表
this
.
handleFetchScheduleList
();
}
// 获取视频课列表
handleFetchScheduleList
=
(
_query
=
{})
=>
{
const
query
=
{
...
this
.
state
.
query
,
...
_query
};
// 更新请求参数
this
.
setState
({
query
});
// window.axios.Apollo('public/apollo/lessonScheduleListPage', query).then((res) => {
// const { result = {} } = res || {};
// const { records = [], total = 0 } = result;
// this.setState({
// dataSource: records,
// totalCount: Number(total)
// });
// });
}
render
()
{
const
{
dataSource
,
totalCount
,
query
}
=
this
.
state
;
return
(
<
div
className=
"page video-course-page"
>
<
div
className=
"content-header"
>
视频课
</
div
>
<
div
className=
"box"
>
{
/* 搜索模块 */
}
<
VideoCourseFilter
onChange=
{
this
.
handleFetchScheduleList
}
/>
{
/* 操作模块 */
}
<
VideoCourseOpt
/>
{
/* 视频课列表模块 */
}
<
VideoCourseList
query=
{
query
}
dataSource=
{
dataSource
}
totalCount=
{
totalCount
}
onChange=
{
this
.
handleFetchScheduleList
}
/>
</
div
>
</
div
>
)
}
}
export
default
VideoCourse
;
src/modules/course-manage/video-course/modal/StudentListModal.jsx
0 → 100644
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-08-14 17:02:59
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-25 14:35:38
* @Description: 视频课学员名单
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Modal
,
Table
,
Button
,
Input
,
Popconfirm
,
message
}
from
'antd'
;
import
Bus
from
'@/core/bus'
;
import
{
PageControl
}
from
"@/components"
;
// import SelectStudent from "../../modal/select-student";
import
hasExportPermission
from
'../../utils/hasExportPermission'
;
import
dealTimeDuration
from
'../../utils/dealTimeDuration'
;
import
'./StudentListModal.less'
const
{
Search
}
=
Input
;
const
STATUS_ENUM
=
{
'NORMAL'
:
'在读'
,
'POTENTIAL'
:
'潜在'
,
'HISTORY'
:
'历史'
,
'ABANDON'
:
'废弃'
,
};
class
StudentListModal
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
const
{
id
}
=
props
.
data
;
this
.
state
=
{
studentList
:
[],
// 学员列表
query
:
{
size
:
10
,
current
:
1
,
queryText
:
null
,
scheduleId
:
id
,
},
total
:
0
,
// 学员总数
}
}
componentWillMount
()
{
this
.
handleFetchStuList
();
}
handleFetchStuList
=
(
current
=
1
)
=>
{
const
{
query
}
=
this
.
state
;
window
.
axios
.
Apollo
(
'public/apollo/getLessonScheduleStuPage'
,
query
)
.
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
||
{};
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
total
:
Number
(
total
),
studentList
:
records
,
})
})
}
// 获取对应课次所有相关学生
// handleAllSelectStuId = () => {
// const { id } = this.props.data;
// return axios.Apollo("public/apollo/getLessonStuIdListByScheduleId", { scheduleId: id }).then(res => {
// const tempArray = [];
// res.data.map(current => {
// tempArray.push({studentId: current})
// })
// this.setState({
// _studentList :tempArray
// }, () => {
// const { query: { scheduleId }, _studentList, allSelectStuId = [] } = this.state;
// let { type = '' } = this.props;
// const studentModal = (
// <SelectStudent
// after={true}
// showTabs={true}
// // type="videoCourse"
// type={type}
// liveCourseId={scheduleId}
// allSelectStuId={allSelectStuId}
// studentList={_studentList}
// onSelect={this.handleSelectStudent}
// close={() => {
// this.setState({
// studentModal: null,
// });
// }}
// />
// )
// this.setState({ studentModal });
// })
// })
// }
parseColumns
=
()
=>
{
const
{
NewVersion
,
currentUserInstInfo
}
=
window
;
const
columns
=
[
{
title
:
"姓名"
,
dataIndex
:
"name"
,
key
:
"name"
},
{
title
:
"手机号"
,
dataIndex
:
"phone"
,
width
:
150
,
key
:
"phone"
,
render
:
(
val
,
record
)
=>
{
if
((
!
NewVersion
&&
!
currentUserInstInfo
.
teacherId
)
||
(
NewVersion
&&
Permission
.
hasEduStudentPhone
()))
{
return
val
;
}
else
{
return
val
.
replace
(
/
(\d{3})(\d{4})(\d{4})
/
,
"$1****$3"
);
}
}
},
{
title
:
'学员类型'
,
key
:
'statusEnum'
,
dataIndex
:
'statusEnum'
,
render
:
(
val
)
=>
{
return
STATUS_ENUM
[
val
];
}
},
{
title
:
'首次观看时间'
,
key
:
'firstWatch'
,
dataIndex
:
'firstWatch'
,
width
:
'20%'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
val
?
formatDate
(
'YYYY-DD-MM H:i:s'
,
val
)
:
'-'
;
}
},
{
title
:
'观看时长'
,
key
:
'watchDuration'
,
dataIndex
:
'watchDuration'
,
width
:
'15%'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
val
?
dealTimeDuration
(
val
)
:
'-'
;
}
},
{
title
:
"操作"
,
dataIndex
:
"operate"
,
key
:
"operate"
,
align
:
'right'
,
render
:
(
text
,
record
)
=>
{
return
(
<
Popconfirm
title=
{
<
span
>
你确定要移出这个学员吗?
<
br
/>
移出的学员将无法观看视频
</
span
>
}
onConfirm=
{
()
=>
{
this
.
handleRemoveStudent
(
record
);
}
}
>
<
span
className=
"operate__item"
>
移出
</
span
>
</
Popconfirm
>
);
},
}
];
return
columns
;
}
// 移出学员
handleRemoveStudent
=
(
record
)
=>
{
const
{
instId
}
=
window
.
currentUserInstInfo
;
const
{
id
}
=
this
.
props
.
data
;
const
{
studentId
}
=
record
;
const
params
=
{
instId
,
scheduleId
:
id
,
studentIds
:
[
studentId
],
}
window
.
axios
.
Apollo
(
'public/apollo/removeLessonScheduleStu'
,
params
)
.
then
((
res
)
=>
{
message
.
success
(
"移除学员成功"
);
this
.
handleFetchStuList
();
this
.
props
.
refresh
();
})
}
// 按照名称或者手机号搜索学员
handleChangeQueryText
=
(
value
)
=>
{
const
query
=
_
.
clone
(
this
.
state
.
query
);
query
.
queryText
=
value
;
query
.
pageNo
=
0
;
if
(
isNaN
(
value
))
{
query
.
name
=
value
delete
query
.
phone
}
else
{
query
.
phone
=
value
delete
query
.
name
}
this
.
setState
({
query
},
()
=>
this
.
handleFetchStuList
());
}
// 排序
handleChagneTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
this
.
state
;
let
{
order
:
_order
}
=
query
;
if
(
columnKey
===
'firstWatch'
&&
order
===
'ascend'
)
{
_order
=
'FIRST_WATCH_ASC'
;
}
if
(
columnKey
===
'firstWatch'
&&
order
===
'descend'
)
{
_order
=
'FIRST_WATCH_DESC'
;
}
if
(
columnKey
===
'watchDuration'
&&
order
===
'ascend'
)
{
_order
=
'WATCH_DURATION_ASC'
;
}
if
(
columnKey
===
'watchDuration'
&&
order
===
'descend'
)
{
_order
=
'WATCH_DURATION_DESC'
;
}
const
_query
=
{
...
query
,
order
:
_order
}
this
.
setState
({
query
:
_query
},
()
=>
this
.
handleFetchStuList
());
}
hanldSelect
=
()
=>
{
const
{
query
:
{
scheduleId
},
studentList
,
allSelectStuId
=
[]
}
=
this
.
state
;
let
{
type
=
''
}
=
this
.
props
;
type
=
!!
type
?
type
:
'videoCourse'
;
if
(
type
===
'videoCourseList'
)
{
// this.handleAllSelectStuId();
return
;
}
// const studentModal = (
// <SelectStudent
// after={true}
// showTabs={true}
// // type="videoCourse"
// type={type}
// liveCourseId={scheduleId}
// allSelectStuId={allSelectStuId}
// studentList={studentList}
// onSelect={this.handleSelectStudent}
// close={() => {
// this.setState({
// studentModal: null,
// });
// }}
// />
// )
this
.
setState
({
studentModal
});
};
handleSelectStudent
=
(
studentList
,
consumeStudentList
,
savedSelectedRows
)
=>
{
const
{
id
}
=
this
.
props
.
data
;
const
{
instId
}
=
window
.
currentUserInstInfo
;
studentList
=
studentList
.
filter
(
item
=>
!!
item
)
const
param
=
{
instId
,
scheduleId
:
id
,
studentIds
:
studentList
};
this
.
setState
({
savedSelectedRows
})
axios
.
Apollo
(
"public/apollo/addLessonScheduleStu"
,
param
).
then
(
res
=>
{
if
(
res
.
success
)
{
message
.
success
(
"学员变更成功"
);
this
.
setState
({
studentModal
:
null
});
this
.
handleFetchStuList
();
this
.
props
.
refresh
();
}
});
}
// 导5.0出
handleExportV5
=
()
=>
{
const
{
id
}
=
this
.
props
.
data
;
window
.
axios
.
Apollo
(
'public/apollo/exportVideoScheduleSync'
,
{
liveCourseId
:
id
}).
then
((
res
)
=>
{
Bus
.
trigger
(
'get_download_count'
);
Modal
.
success
({
title
:
'导出任务提交成功'
,
content
:
'请前往右上角的“任务中心”进行下载'
,
okText
:
'我知道了'
,
});
})
}
// 4.0导出
handleExport
=
()
=>
{
const
{
id
}
=
this
.
props
.
data
;
window
.
axios
.
post
(
'api-b/b/lesson/exportVideoScheduleSync'
,
{
liveCourseId
:
id
}).
then
((
res
)
=>
{
Bus
.
trigger
(
'get_download_count'
);
Modal
.
success
({
title
:
'导出任务提交成功'
,
content
:
'请前往右上角的“导出中心”进行下载'
,
okText
:
'我知道了'
,
});
})
}
render
()
{
const
isTeacher
=
!!
window
.
currentUserInstInfo
.
teacherId
;
const
{
studentList
,
total
,
query
}
=
this
.
state
;
const
{
current
,
size
,
queryText
}
=
query
;
return
(
<
Modal
title=
"查看学员名单"
visible=
{
true
}
width=
{
680
}
footer=
{
null
}
className=
"video-course-student-list-modal"
onCancel=
{
this
.
props
.
close
}
>
{
/* 任意状态都可以添加学员 */
}
<
div
className=
"video-course-student-list-modal__operate"
>
{
!
isTeacher
&&
<
Button
type=
"primary"
onClick=
{
this
.
hanldSelect
}
>
添加上课学员
</
Button
>
}
{
// 有导出权限的机构显示导出按钮
hasExportPermission
(
'videoClass'
)
&&
<
Button
onClick=
{
()
=>
{
if
(
!
studentList
.
length
)
{
message
.
warning
(
'暂无数据可导出'
);
return
;
}
if
(
window
.
NewVersion
)
{
this
.
handleExportV5
();
}
else
{
this
.
handleExport
();
}
}
}
className=
"export-btn"
>
导出
</
Button
>
}
<
Search
placeholder=
"搜索学员姓名/手机号"
style=
{
{
width
:
200
}
}
onSearch=
{
this
.
handleChangeQueryText
}
className=
"search"
/>
</
div
>
<
Table
size=
"small"
columns=
{
this
.
parseColumns
()
}
dataSource=
{
studentList
}
pagination=
{
false
}
scroll=
{
{
y
:
400
}
}
onChange=
{
this
.
handleChagneTable
}
/>
<
PageControl
size=
"small"
current=
{
current
-
1
}
pageSize=
{
size
}
total=
{
total
}
toPage=
{
(
page
)
=>
{
query
.
current
=
page
+
1
;
this
.
handleFetchStuList
();
}
}
/>
{
this
.
state
.
studentModal
}
</
Modal
>
)
}
}
export
default
StudentListModal
;
src/modules/course-manage/video-course/modal/StudentListModal.less
0 → 100644
View file @
fdf7e07d
.video-course-student-list-modal {
&__operate {
position: relative;
margin-bottom: 16px;
.export-btn {
margin-left: 8px;
}
.search {
position: absolute;
right: 0;
}
}
.operate__item {
color: #FF8534;
cursor: pointer;
}
}
\ No newline at end of file
src/modules/store-manege/StoreDecorationPage.tsx
deleted
100644 → 0
View file @
93970161
/*
* @Author: wufan
* @Date: 2020-11-30 10:47:38
* @LastEditors: wufan
* @LastEditTime: 2020-11-30 17:35:24
* @Description: 员工管理页面
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
withRouter
}
from
"react-router-dom"
;
import
_
from
"underscore"
;
import
PageControl
from
"@/components/PageControl"
;
import
{
Table
,
Modal
,
message
,
Row
,
Col
,
Input
,
DatePicker
,
Button
,
}
from
"antd"
;
import
{
QuestionCircleOutlined
}
from
"@ant-design/icons"
;
import
StoreService
from
"@/domains/store-domain/storeService"
;
import
"./StoreDecorationPage.less"
;
import
moment
from
"moment"
;
const
{
confirm
}
=
Modal
;
const
{
Search
}
=
Input
;
const
{
RangePicker
}
=
DatePicker
;
declare
var
window
:
any
;
interface
RecordTypes
{
storeUserId
:
string
;
role
:
string
;
}
function
StoreDecorationPage
()
{
const
[
storeDecorationlist
,
setStoreDecorationlist
]
=
useState
([
{
name
:
"赵云"
,
phone
:
"18767118672"
,
role
:
"0"
,
storeUserId
:
""
,
},
{
name
:
"吕布"
,
phone
:
"18767118672"
,
role
:
"0"
,
storeUserId
:
""
,
},
]);
const
[
query
,
setQuery
]
=
useState
({
current
:
0
,
size
:
10
,
name
:
""
,
phone
:
""
,
identity
:
"ALL"
,
instId
:
"1837447"
||
window
.
currentUserInstInfo
.
instId
,
registerStartDate
:
null
,
registerEndDate
:
null
,
});
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
model
,
setModel
]
=
useState
(
null
);
const
[
isModalOpen
,
setIsModalOpen
]
=
useState
(
false
);
const
[
isManager
,
setIsManager
]
=
useState
(
true
);
const
[
isNormal
,
setIsNormal
]
=
useState
(
true
);
const
[
choosedItem
,
setChooseItem
]
=
useState
({});
useEffect
(()
=>
{
// getStoreDecorationList();
},
[
query
]);
function
getStoreDecorationList
()
{
let
_query
=
_
.
clone
(
query
);
_query
.
current
=
query
.
current
+
1
;
StoreService
.
getStoreDecorationList
(
_query
).
then
((
res
:
any
)
=>
{
console
.
log
(
res
.
result
.
records
);
setStoreDecorationlist
(
res
.
result
.
records
);
setTotal
(
res
.
result
.
total
);
});
}
function
handleReplaceDecoration
(
record
:
RecordTypes
)
{}
function
handleDeleteDecoration
(
record
:
RecordTypes
)
{}
function
handleDeleteDecorationConfirm
(
record
:
RecordTypes
)
{
return
confirm
({
title
:
"你确定要删除这个banner吗?"
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
okText
:
"删除"
,
cancelText
:
"取消"
,
onOk
:
()
=>
{
handleDeleteDecoration
(
record
);
},
});
}
function
parseColumn
()
{
return
[
{
title
:
"用户姓名"
,
dataIndex
:
"name"
,
render
:
(
val
:
string
)
=>
{
return
(
<
div
className=
"coupon-info"
>
<
span
className=
"title"
>
{
val
}
</
span
>
</
div
>
);
},
},
{
title
:
"手机号"
,
dataIndex
:
"phone"
,
key
:
"phone"
,
render
:
(
val
:
string
)
=>
{
return
<
div
>
{
val
}
</
div
>;
},
},
{
title
:
"注册时间"
,
dataIndex
:
"registerDate"
,
key
:
"registerDate"
,
render
:
(
val
:
string
)
=>
{
return
<
div
>
{
moment
(
val
).
format
(
"YYYY-MM-DD HH:mm:ss"
)
}
</
div
>;
},
},
{
title
:
"操作"
,
dataIndex
:
"operation"
,
render
:
(
val
:
string
,
record
:
RecordTypes
)
=>
{
return
record
.
role
===
""
||
record
.
role
===
"1"
?
(
<
div
className=
"no-operate"
>
-
</
div
>
)
:
(
<
div
className=
"operation"
>
<
span
className=
"edit"
onClick=
{
()
=>
handleReplaceDecoration
(
record
)
}
>
替换
</
span
>
<
span
className=
"divider-line"
>
{
" | "
}
</
span
>
<
span
className=
"delete"
onClick=
{
()
=>
handleDeleteDecoration
(
record
)
}
>
删除
</
span
>
</
div
>
);
},
},
];
}
function
handleQuery
(
name
:
string
,
value
:
any
)
{
const
_query
=
_
.
clone
(
query
);
// _query[name] = value;
setQuery
(
_query
);
}
function
handleToAddStoreDecoration
()
{}
return
(
<
div
className=
"page user-manage-page"
>
<
div
className=
"page-content"
>
<
div
className=
"content-header"
>
店铺装修
</
div
>
<
div
className=
"box"
>
<
div
className=
"box-header"
>
<
div
style=
{
{
display
:
"flex"
,
alignItems
:
"center"
,
justifyContent
:
"space-between"
,
padding
:
"15px 0 10px"
,
}
}
>
<
div
style=
{
{
flex
:
1
}
}
>
banner设置
</
div
>
</
div
>
<
Button
onClick=
{
()
=>
{
handleToAddStoreDecoration
();
}
}
type=
"primary"
className=
"add-show-btn"
>
添加Banner
</
Button
>
</
div
>
<
div
className=
"box-body"
>
<
Table
size=
{
"middle"
}
pagination=
{
false
}
dataSource=
{
storeDecorationlist
}
columns=
{
parseColumn
()
}
rowKey=
{
(
item
:
any
)
=>
item
.
id
}
bordered
/>
</
div
>
<
div
className=
"box-footer"
>
<
PageControl
current=
{
query
.
current
}
pageSize=
{
query
.
size
}
total=
{
total
}
toPage=
{
(
page
)
=>
{
const
queryStates
=
_
.
clone
(
query
);
queryStates
.
current
=
page
;
setQuery
(
queryStates
);
}
}
/>
</
div
>
</
div
>
</
div
>
</
div
>
);
}
export
default
withRouter
(
StoreDecorationPage
);
src/routes/config/mainRoutes.tsx
View file @
fdf7e07d
/*
* @Author: 吴文洁
* @Date: 2020-04-29 10:26:32
* @LastEditors:
wuf
an
* @LastEditTime: 2020-12-
16 16:39:03
* @LastEditors:
zhangleyu
an
* @LastEditTime: 2020-12-
25 15:20:14
* @Description: 内容线路由配置
*/
import
EmployeesManagePage
from
'@/modules/store-manage/EmployeesManagePage'
;
...
...
@@ -12,8 +12,9 @@ import StoreDecorationPage from '@/modules/store-manage/StoreDecorationPage';
import
CourseCatalogPage
from
'@/modules/store-manage/CourseCatalogPage'
;
import
LiveCoursePage
from
'@/modules/course-manage/LiveCoursePage'
;
import
AddLivePage
from
'@/modules/course-manage/AddLive'
import
VideoCoursePage
from
'@/modules/course-manage/video-course'
import
AddVideoCoursePage
from
'@/modules/course-manage/video-course/AddVideoCourse'
import
DataList
from
'@/modules/course-manage/DataList/DataList'
;
import
ClassBook
from
'@/modules/resource-disk'
;
const
mainRoutes
=
[
...
...
@@ -45,7 +46,12 @@ const mainRoutes = [
{
path
:
'/live-course'
,
component
:
LiveCoursePage
,
name
:
'课程管理'
name
:
'直播课'
},
{
path
:
'/video-course'
,
component
:
VideoCoursePage
,
name
:
'视频课'
},
{
path
:
'/create-live-course'
,
...
...
@@ -53,10 +59,16 @@ const mainRoutes = [
name
:
'创建直播课'
},
{
path
:
'/create-video-course'
,
component
:
AddVideoCoursePage
,
name
:
'创建视频课'
},
{
path
:
'/resource-disk'
,
component
:
ClassBook
,
name
:
'资料云盘'
},
]
export
default
mainRoutes
;
\ No newline at end of file
src/routes/config/menuList.tsx
View file @
fdf7e07d
...
...
@@ -9,11 +9,11 @@ export const menuList: any = [
groupCode
:
"CourseLiveClass"
,
link
:
'/live-course'
},
//
{
//
groupName: "视频课",
//
groupCode: "CourseVideoClass",
// link: '/CourseVideoClass
'
//
}
{
groupName
:
"视频课"
,
groupCode
:
"CourseVideoClass"
,
link
:
'/video-course
'
}
]
},
{
...
...
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