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
e926cbc4
Commit
e926cbc4
authored
Jan 15, 2021
by
zhangleyuan
Browse files
Options
Browse Files
Download
Plain Diff
feat:解决合并代码后的冲突
parents
d519df0b
0edaa54e
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
44 changed files
with
2025 additions
and
209 deletions
+2025
-209
CHANGE_LOG.md
+8
-1
src/bu-components/ShareLiveModal.jsx
+0
-1
src/common/js/axios.ts
+3
-3
src/common/js/service.ts
+2
-2
src/components/DownloadLiveModal.jsx
+13
-28
src/components/ImgCutModalNew.jsx
+6
-5
src/data-source/base/request-apis.ts
+4
-1
src/data-source/course/request-api.ts
+31
-2
src/domains/basic-domain/baseService.ts
+6
-2
src/domains/basic-domain/constants.ts
+3
-3
src/domains/course-domain/CourseService.ts
+38
-5
src/domains/course-domain/constants.ts
+14
-11
src/index.html
+2
-2
src/modules/common/DateRangePicker.jsx
+1
-2
src/modules/course-manage/AddLive.jsx
+6
-28
src/modules/course-manage/DataList/CourseData.jsx
+2
-2
src/modules/course-manage/DataList/DataList.less
+3
-0
src/modules/course-manage/components/AddLiveBasic.jsx
+7
-4
src/modules/course-manage/components/AddLiveClass.jsx
+48
-36
src/modules/course-manage/components/AddLiveIntro.jsx
+3
-3
src/modules/course-manage/components/LiveCourseFilter.jsx
+19
-4
src/modules/course-manage/components/LiveCourseList.jsx
+0
-0
src/modules/course-manage/components/LiveCourseList.less
+10
-2
src/modules/course-manage/components/LiveCourseOpt.jsx
+21
-18
src/modules/course-manage/modal/PreviewCourseModal.jsx
+23
-10
src/modules/course-manage/modal/ShareLiveModal.jsx
+42
-24
src/modules/course-manage/modal/ShareLiveModal.less
+5
-0
src/modules/course-manage/video-course/AddVideoCourse.jsx
+0
-0
src/modules/course-manage/video-course/AddVideoCourse.less
+140
-0
src/modules/course-manage/video-course/components/AddVideoIntro.jsx
+286
-0
src/modules/course-manage/video-course/components/AddVideoIntro.less
+266
-0
src/modules/course-manage/video-course/components/VideoCourseFilter.jsx
+239
-0
src/modules/course-manage/video-course/components/VideoCourseFilter.less
+45
-0
src/modules/course-manage/video-course/components/VideoCourseList.jsx
+343
-0
src/modules/course-manage/video-course/components/VideoCourseList.less
+67
-0
src/modules/course-manage/video-course/components/VideoCourseOpt.less
+8
-0
src/modules/course-manage/video-course/components/VieoCourseOpt.jsx
+28
-0
src/modules/course-manage/video-course/index.jsx
+85
-0
src/modules/course-manage/video-course/modal/WatchDataModal.jsx
+167
-0
src/modules/course-manage/video-course/modal/WatchDataModal.less
+7
-0
src/modules/root/Header.tsx
+1
-1
src/modules/root/Login.jsx
+1
-1
src/routes/config/mainRoutes.tsx
+17
-3
src/routes/config/menuList.tsx
+5
-5
No files found.
CHANGE_LOG.md
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
*
@Author: zhangleyuan
*
@Date: 2020-12-15 19:58:31
*
@LastEditors: zhangleyuan
*
@LastEditTime: 202
0-12-15 20:00:31
*
@LastEditTime: 202
1-01-04 20:10:06
*
@Description: 描述一下
*
@@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
-->
...
...
@@ -13,3 +13,9 @@
+
播种计划一期第一阶段初上线
#### 1.0.1
`2020-01-04`
+
播种计划一期第二阶段初上线
\ No newline at end of file
src/bu-components/ShareLiveModal.jsx
View file @
e926cbc4
...
...
@@ -117,7 +117,6 @@ class ShareLiveModal extends React.Component {
>
{
`【${courseName}】开课啦,快来学习!`
}
</
div
>
<
img
src=
{
coverImgSrc
}
crossOrigin=
"*"
className=
"course-cover"
alt=
"course-cover"
/>
...
...
src/common/js/axios.ts
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:31
* @LastEditors: zhangleyuan
* @LastEditTime: 202
0-12-22 15:24:03
* @LastEditTime: 202
1-01-09 14:39:46
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -27,7 +27,7 @@ interface HeadersType{
storeId
?:
any
,
storeUserId
?:
any
,
userId
?:
any
,
token
?:
any
xm
token
?:
any
}
class
Axios
{
static
post
(
...
...
@@ -49,7 +49,7 @@ class Axios {
headerObject
.
userId
=
User
.
getUserId
();
}
if
(
User
.
getToken
()){
headerObject
.
token
=
User
.
getToken
();
headerObject
.
xm
token
=
User
.
getToken
();
}
const
instance
:
AxiosInstance
=
axios
.
create
({
timeout
:
TIME_OUT
,
...
...
src/common/js/service.ts
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:51
* @LastEditors: wufan
* @LastEditTime: 202
0-12-17 14:14:43
* @LastEditTime: 202
1-01-06 20:18:46
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -23,7 +23,7 @@ class Service {
return
Axios
.
post
(
'POST'
,
`hades/
${
url
}
`
,
params
,
option
);
}
static
Sales
(
url
:
string
,
params
:
any
,
option
:
any
)
{
static
Sales
(
url
:
string
,
params
:
any
,
option
?
:
any
)
{
return
Axios
.
post
(
'POST'
,
`sales/
${
url
}
`
,
params
,
option
);
}
...
...
src/components/DownloadLiveModal.jsx
View file @
e926cbc4
import
React
from
'react'
import
React
from
'react'
;
import
{
Modal
,
Button
}
from
"antd"
;
import
"./DownloadLiveModal.less"
...
...
@@ -12,37 +13,12 @@ class DownloadLiveModal extends React.Component {
type
:
'pre'
,
}
}
downloadLiveClient
(){
if
(
type
===
'pre'
)
{
const
isMac
=
/macintosh|mac os x/i
.
test
(
navigator
.
userAgent
);
if
(
isMac
){
Modal
.
info
({
title
:
"抱歉,暂不支持Mac版"
,
content
:
"Mac版正在开发中,敬请期待"
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
okText
:
'我知道了'
});
return
;
}
url
&&
window
.
open
(
url
);
this
.
setState
({
image
:
'https://image.xiaomaiketang.com/xm/wPwRdaa7MM.png'
,
tip
:
'安装完成后,再次打开即可开始直播。'
,
text
:
'我知道了'
,
type
:
'finish'
,
})
}
else
{
this
.
props
.
onCancel
();
}
}
render
()
{
const
{
url
}
=
this
.
props
;
const
{
image
,
tip
,
text
,
type
}
=
this
.
state
;
return
<
Modal
visible=
{
true
}
maskClosable=
{
false
}
title=
"下载客户端"
className=
"download-live-modal"
footer=
{
null
}
...
...
@@ -56,8 +32,17 @@ class DownloadLiveModal extends React.Component {
type=
"primary"
className=
"download-button"
onClick=
{
()
=>
{
if
(
type
===
'pre'
)
{
url
&&
window
.
open
(
url
);
this
.
setState
({
image
:
'https://image.xiaomaiketang.com/xm/wPwRdaa7MM.png'
,
tip
:
'安装完成后,再次打开即可开始直播。'
,
text
:
'我知道了'
,
type
:
'finish'
,
})
}
else
{
this
.
props
.
onCancel
();
}
}
}
>
{
text
}
</
Button
>
</
Modal
>
...
...
src/components/ImgCutModalNew.jsx
View file @
e926cbc4
...
...
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import
{
Modal
,
Button
}
from
'antd'
;
import
Service
from
'@/common/js/service'
;
import
User
from
'@/common/js/user'
;
import
PhotoClip
from
'photoclip'
let
cutFlag
=
false
;
class
ImgCutModalNew
extends
React
.
Component
{
...
...
@@ -30,10 +31,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 +42,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/data-source/base/request-apis.ts
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
* @Author: wufan
* @Date: 2020-12-01 17:21:21
* @LastEditors: zhangleyuan
* @LastEditTime: 202
0-12-22 15:39:00
* @LastEditTime: 202
1-01-09 11:06:42
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -38,6 +38,9 @@ export function sendNewPhoneAuthCode(params: object) {
export
function
editUserPhone
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/editUserPhone"
,
params
);
}
export
function
getLastedVersion
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/getLastedVersion"
,
params
);
}
export
const
getOssClient
=
(
data
:
object
,
instId
:
string
,
...
...
src/data-source/course/request-api.ts
View file @
e926cbc4
/*
* @Author: wufan
* @Date: 2020-12-12 11:57:10
* @LastEditors:
zhangleyu
an
* @LastEditTime: 202
0-12-16 16:14:42
* @LastEditors:
wuf
an
* @LastEditTime: 202
1-01-06 20:18:16
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -12,6 +12,9 @@ import Service from "@/common/js/service";
export
function
fetchLecturerData
(
params
:
object
)
{
return
Service
.
Hades
(
"public/courseCloud/queryTeacherVisitData"
,
params
);
}
export
function
getQrcode
(
params
:
object
)
{
return
Service
.
Sales
(
"public/businessShow/convertShortUrls"
,
params
);
}
export
function
fetchUserData
(
params
:
object
)
{
return
Service
.
Hades
(
"public/courseCloud/queryStudentVisitData"
,
params
);
...
...
@@ -48,4 +51,29 @@ export function turnOnOrOffLiveCloudCourse(params: object) {
}
export
function
delLiveCloudCourse
(
params
:
object
)
{
return
Service
.
Hades
(
"public/courseCloud/delLiveCloudCourse"
,
params
);
}
//视频课相关接口
export
function
changeVideoShelfState
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/changeVideoShelfState"
,
params
);
}
export
function
createVideoSchedule
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/createVideoSchedule"
,
params
);
}
export
function
delVideoSchedule
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/delVideoSchedule"
,
params
);
}
export
function
editVideoSchedule
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/editVideoSchedule"
,
params
);
}
export
function
userWatchInfo
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/userWatchInfo"
,
params
);
}
export
function
videoScheduleDetail
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/videoScheduleDetail"
,
params
);
}
export
function
videoSchedulePage
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/videoSchedulePage"
,
params
);
}
export
function
videoWatchInfo
(
params
:
object
)
{
return
Service
.
Hades
(
"public/hades/videoWatchInfo"
,
params
);
}
\ No newline at end of file
src/domains/basic-domain/baseService.ts
View file @
e926cbc4
...
...
@@ -2,12 +2,12 @@
* @Author: wufan
* @Date: 2020-12-01 17:20:49
* @LastEditors: zhangleyuan
* @LastEditTime: 202
0-12-11 11:36:19
* @LastEditTime: 202
1-01-09 11:08:02
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
{
getUserStore
,
getUserPermission
,
logout
,
getStoreUser
,
sendBizAuthCode
,
editUserPhone
,
checkBizAuthCode
,
sendNewPhoneAuthCode
,
sendLoginAuthCode
,
login
}
from
'@/data-source/base/request-apis'
;
import
{
getUserStore
,
getUserPermission
,
logout
,
getStoreUser
,
sendBizAuthCode
,
editUserPhone
,
checkBizAuthCode
,
sendNewPhoneAuthCode
,
sendLoginAuthCode
,
login
,
getLastedVersion
}
from
'@/data-source/base/request-apis'
;
export
default
class
StoreService
{
// 获取员工列表
...
...
@@ -46,4 +46,7 @@ export default class StoreService {
static
login
(
params
:
any
){
return
login
(
params
);
}
static
getLastedVersion
(
params
:
any
){
return
getLastedVersion
(
params
);
}
}
\ No newline at end of file
src/domains/basic-domain/constants.ts
View file @
e926cbc4
/*
* @Author: 陈剑宇
* @Date: 2020-05-07 14:43:01
* @LastEditTime: 2021-01-
04 11:21:06
* @LastEditTime: 2021-01-
14 19:31:30
* @LastEditors: zhangleyuan
* @Description:
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
...
...
@@ -25,5 +25,6 @@ export const USER_TYPE: string = 'B';
export
const
PROJECT
=
'xmzj-web-b'
;
export
const
VERSION
=
'5.4.8'
;
export
const
PREFIX
=
'cloud-class'
;
// host
export
const
BASIC_HOST
:
string
=
BASIC_HOST_MAP
[
ENV
];
\ No newline at end of file
export
const
BASIC_HOST
:
string
=
BASIC_HOST_MAP
[
ENV
];
src/domains/course-domain/CourseService.ts
View file @
e926cbc4
/*
* @Author: wufan
* @Date: 2020-11-25 18:25:02
* @LastEditors:
zhangleyu
an
* @LastEditTime: 202
0-12-16 16:15:15
* @LastEditors:
wuf
an
* @LastEditTime: 202
1-01-06 20:17:40
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
{
fetchLecturerData
,
fetchUserData
,
exportStudentCourseData
,
exportPlayBackCourseData
,
fetchPlaybackList
,
createLiveCloudCourse
,
getLiveCloudCoursePage
,
getLiveCloudCourseDetail
,
updateLiveCloudCourse
,
turnOnOrOffLiveCloudCourse
,
delLiveCloudCourse
}
from
'@/data-source/course/request-api'
;
import
{
fetchLecturerData
,
fetchUserData
,
exportStudentCourseData
,
exportPlayBackCourseData
,
fetchPlaybackList
,
createLiveCloudCourse
,
getLiveCloudCoursePage
,
getLiveCloudCourseDetail
,
updateLiveCloudCourse
,
turnOnOrOffLiveCloudCourse
,
delLiveCloudCourse
,
changeVideoShelfState
,
createVideoSchedule
,
delVideoSchedule
,
editVideoSchedule
,
userWatchInfo
,
videoSchedulePage
,
videoScheduleDetail
,
videoWatchInfo
,
getQrcode
}
from
'@/data-source/course/request-api'
;
export
default
class
courseService
{
// 获取讲师上课数据
...
...
@@ -14,6 +17,11 @@ export default class courseService {
return
fetchLecturerData
(
params
);
}
// 生成二维码
static
getQrcode
(
params
:
any
)
{
return
getQrcode
(
params
);
}
// 获取用户上课数据
static
fetchUserData
(
params
:
any
)
{
return
fetchUserData
(
params
);
...
...
@@ -24,7 +32,7 @@ export default class courseService {
static
getLiveCloudCoursePage
(
params
:
any
)
{
return
getLiveCloudCoursePage
(
params
);
}
// 导出学生上课数据
static
exportStudentCourseData
(
params
:
any
)
{
return
exportStudentCourseData
(
params
);
...
...
@@ -39,7 +47,7 @@ export default class courseService {
static
fetchPlaybackList
(
params
:
any
)
{
return
fetchPlaybackList
(
params
);
}
static
getLiveCloudCourseDetail
(
params
:
any
)
{
return
getLiveCloudCourseDetail
(
params
);
}
...
...
@@ -52,4 +60,28 @@ export default class courseService {
static
delLiveCloudCourse
(
params
:
any
)
{
return
delLiveCloudCourse
(
params
);
}
static
changeVideoShelfState
(
params
:
any
)
{
return
changeVideoShelfState
(
params
);
}
static
createVideoSchedule
(
params
:
any
)
{
return
createVideoSchedule
(
params
);
}
static
delVideoSchedule
(
params
:
any
)
{
return
delVideoSchedule
(
params
);
}
static
editVideoSchedule
(
params
:
any
)
{
return
editVideoSchedule
(
params
);
}
static
userWatchInfo
(
params
:
any
)
{
return
userWatchInfo
(
params
);
}
static
videoSchedulePage
(
params
:
any
)
{
return
videoSchedulePage
(
params
);
}
static
videoScheduleDetail
(
params
:
any
)
{
return
videoScheduleDetail
(
params
);
}
static
videoWatchInfo
(
params
:
any
)
{
return
videoWatchInfo
(
params
);
}
}
\ No newline at end of file
src/domains/course-domain/constants.ts
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-08-20 09:21:40
* @LastEditors:
wuf
an
* @LastEditTime: 202
0-12-12 11:18:53
* @LastEditors:
zhangleyu
an
* @LastEditTime: 202
1-01-11 15:35:49
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
{
MapInterface
}
from
'@/domains/basic-domain/interface'
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'
dev
'
;
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'
rc
'
;
const
appIdMap
:
MapInterface
=
{
dev
:
'wx3ea60e78ddfa277e'
,
dev1
:
'wx3ea60e78ddfa277e'
,
rc
:
'wx5c5a1fb71ecab7bc'
,
gray
:
"wx
dd6b458500d4c224
"
,
// 小麦校讯通
prod
:
'wx
dd6b458500d4c224
'
gray
:
"wx
3dda02036493ada6
"
,
// 小麦校讯通
prod
:
'wx
3dda02036493ada6
'
}
const
shareUrlMap
:
MapInterface
=
{
...
...
@@ -25,14 +25,17 @@ const shareUrlMap: MapInterface = {
'gray'
:
'https://prod.xiaomai5.com/share/show?appid='
}
const
LIVE_SHARE_MAP
:
MapInterface
=
{
dev
:
'https://dev.xiaomai5.com/
xiaomai-live-shar
e/index.html#/'
,
dev1
:
'https://dev.xiaomai5.com/
xiaomai-live-shar
e/index.html#/'
,
rc
:
'https://rc.xiaomai5.com/
xiaomai-live-shar
e/index.html#/'
,
gray
:
'https://res.xiaomai
5.com/xiaomai-live-shar
e/gray/index.html#/'
,
prod
:
'https://res.xiaomai
5.com/xiaomai-live-shar
e/index.html#/'
,
const
LIVE_SHARE_MAP
:
MapInterface
=
{
dev
:
'https://dev.xiaomai5.com/
store-liv
e/index.html#/'
,
dev1
:
'https://dev.xiaomai5.com/
store-liv
e/index.html#/'
,
rc
:
'https://rc.xiaomai5.com/
store-liv
e/index.html#/'
,
gray
:
'https://res.xiaomai
0.com/store-liv
e/gray/index.html#/'
,
prod
:
'https://res.xiaomai
0.com/store-liv
e/index.html#/'
,
}
export
const
appId
:
string
=
appIdMap
[
ENV
];
export
const
shareUrl
:
string
=
shareUrlMap
[
ENV
];
export
const
LIVE_SHARE
:
string
=
LIVE_SHARE_MAP
[
ENV
];
src/index.html
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors: zhangleyuan
* @LastEditTime: 202
0-12-30 13:58:49
* @LastEditTime: 202
1-01-12 15:26:36
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
...
...
@@ -36,7 +36,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>
小麦
云课堂
</title>
<title>
小麦
企培
</title>
<script
type=
"text/javascript"
charset=
"utf-8"
src=
"//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"
></script>
</head>
...
...
src/modules/common/DateRangePicker.jsx
View file @
e926cbc4
...
...
@@ -13,13 +13,12 @@ class DateRangePicker extends React.Component {
}
render
()
{
const
showTime
=
{
showTime
:
tru
e
}
const
showTime
=
{
showTime
:
fals
e
}
return
(
<
RangePicker
{
...
this
.
props
}
format=
{
this
.
props
.
format
||
'YYYY-MM-DD'
}
allowClear=
{
this
.
props
.
allowClear
}
ranges=
{
this
.
props
.
ranges
||
{
'本月'
:
[
moment
().
startOf
(
'month'
),
moment
().
endOf
(
'month'
)],
'本周'
:
[
moment
().
startOf
(
'week'
),
moment
().
endOf
(
'week'
)],
'上月'
:
[
moment
().
subtract
(
1
,
'M'
).
startOf
(
'month'
),
moment
().
subtract
(
1
,
'M'
).
endOf
(
'month'
)],
'上周'
:
[
moment
().
subtract
(
1
,
'w'
).
startOf
(
'week'
),
moment
().
subtract
(
1
,
'w'
).
endOf
(
'week'
)]
}
}
onChange=
{
(
date
)
=>
{
if
(
!
_
.
isEmpty
(
date
))
{
date
[
0
]
=
date
[
0
].
startOf
(
'day'
)
...
...
src/modules/course-manage/AddLive.jsx
View file @
e926cbc4
...
...
@@ -82,6 +82,7 @@ class AddLive extends React.Component {
teacherId
:
null
,
teacherName
:
null
,
assistant
:[],
assistantNames
:[],
liveDate
:
null
,
timeHorizonStart
:
null
,
timeHorizonEnd
:
null
,
...
...
@@ -169,6 +170,7 @@ class AddLive extends React.Component {
const
timeHorizonStart
=
startTime
;
const
timeHorizonEnd
=
endTime
;
const
assistant
=
_
.
pluck
(
admins
,
"adminId"
);
const
assistantNames
=
_
.
pluck
(
admins
,
"adminName"
);
const
addLiveClassInfo
=
{
assistant
,
liveDate
,
...
...
@@ -179,6 +181,7 @@ class AddLive extends React.Component {
timeHorizonEnd
,
startTime
,
endTime
,
assistantNames
}
// liveCourseMediaRequests = liveCourseMediaRequests.length
...
...
@@ -388,7 +391,7 @@ handleChangeBasicInfo = (field, value) => {
message
.
warning
(
'请选择上课日期'
);
resolve
(
false
);
return
;
}
else
if
(
startTime
===
endTime
)
{
}
else
if
(
startTime
===
endTime
||
startTime
>
endTime
)
{
message
.
warning
(
'结束时间必须晚于开始时间'
);
resolve
(
false
);
return
;
...
...
@@ -444,36 +447,11 @@ handleChangeBasicInfo = (field, value) => {
}
}
if
(
!
teacherId
){
message
.
warning
(
'
上课老师不能为空
'
);
message
.
warning
(
'
请选择上课老师
'
);
resolve
(
false
);
return
;
}
resolve
(
true
)
// if(!teacherId) {
// message.warning('上课老师不能为空');
// resolve(false);
// return;
// } else if(!applyMode) {
// message.warning('请选择分享设置');
// resolve(false);
// return;
// } else {
// const textIntro = liveCourseMediaRequests.filter(item => { return item.mediaType === 'TEXT'; });
// for (let i = 0, len = textIntro.length; i < len; i++) {
// if (textIntro[i].mediaContent && textIntro[i].mediaContentLength.length > 1000) {
// message.warning(`第${i+1}个文字简介的字数超过了1000个字`);
// resolve(false);
// return;
// }
// }
// }
// if(window.NewVersion && type === 'add') {
// this.handleValidateLackConsumeModal(consumeHourNum, calendarTime, consumeStudentList).then(res => {
// resolve(res)
// })
// } else {
// resolve(true);
// }
});
}
...
...
@@ -537,7 +515,7 @@ handleChangeBasicInfo = (field, value) => {
/>
<
div
className=
"box"
>
<
div
className=
"show-tips"
>
<
ShowTips
message=
"请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦
助教
保有依据国家规定及平台规则进行处理的权利"
/>
<
ShowTips
message=
"请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦
企培
保有依据国家规定及平台规则进行处理的权利"
/>
</
div
>
<
div
className=
"add-live-page__form"
>
<
div
className=
"basic-info__wrap"
>
...
...
src/modules/course-manage/DataList/CourseData.jsx
View file @
e926cbc4
...
...
@@ -151,8 +151,8 @@ class DataList extends React.Component {
},
{
title
:
"累计在线时长"
,
dataIndex
:
"
watch
Duration"
,
sorter
:
(
a
,
b
)
=>
a
.
watchDuration
-
b
.
watch
Duration
,
dataIndex
:
"
total
Duration"
,
sorter
:
(
a
,
b
)
=>
a
.
totalDuration
-
b
.
total
Duration
,
sortDirections
:
[
"descend"
,
"ascend"
],
render
:
(
text
,
record
)
=>
{
//如无离开时间,就置空
...
...
src/modules/course-manage/DataList/DataList.less
View file @
e926cbc4
...
...
@@ -95,6 +95,9 @@
&.avatar-name-phone {
justify-content: flex-start;
padding-left: 26px;
.avatar{
border-radius:50%;
}
.name {
height: 22px;
font-size: 16px;
...
...
src/modules/course-manage/components/AddLiveBasic.jsx
View file @
e926cbc4
...
...
@@ -30,7 +30,8 @@ class AddLiveBasic extends React.Component {
showCutModal
:
false
,
courseCatalogList
:[],
showSelectFileModal
:
false
,
cutImageBlob
:
null
cutImageBlob
:
null
,
hasImgReady
:
false
// 图片是否上传成功
}
}
componentWillUnmount
()
{
...
...
@@ -71,7 +72,6 @@ class AddLiveBasic extends React.Component {
}
catalogChange
=
(
value
)
=>
{
console
.
log
(
'111'
);
const
changeValueLength
=
value
.
length
;
switch
(
changeValueLength
){
case
1
:
...
...
@@ -143,6 +143,7 @@ class AddLiveBasic extends React.Component {
const
_dataUrl
=
this
.
clip
()
self
.
setState
({
dataUrl
:
_dataUrl
,
hasImgReady
:
true
})
},
100
)
...
...
@@ -198,7 +199,8 @@ class AddLiveBasic extends React.Component {
}
render
()
{
const
{
showCutModal
,
imageFile
,
courseCatalogList
,
showSelectFileModal
,
visible
,
cutImageBlob
}
=
this
.
state
;
const
{
showCutModal
,
imageFile
,
courseCatalogList
,
showSelectFileModal
,
visible
,
cutImageBlob
,
hasImgReady
}
=
this
.
state
;
const
{
data
,
pageType
,
isEdit
}
=
this
.
props
;
const
{
courseName
,
categoryName
,
coverUrl
}
=
data
;
const
fileName
=
''
;
...
...
@@ -255,7 +257,7 @@ class AddLiveBasic extends React.Component {
<
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=
"请选择课程分类"
/>
<
Cascader
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=
"请选择课程分类"
/>
...
...
@@ -312,6 +314,7 @@ class AddLiveBasic extends React.Component {
<
Button
key=
"submit"
type=
"primary"
disabled=
{
!
hasImgReady
}
onClick=
{
()
=>
{
if
(
!
cutFlag
)
{
cutFlag
=
true
;
...
...
src/modules/course-manage/components/AddLiveClass.jsx
View file @
e926cbc4
...
...
@@ -48,6 +48,7 @@ class AddLiveClass extends React.Component {
this
.
getTeacherList
();
this
.
getAssistantList
();
}
getTeacherList
(
current
=
1
,
selectList
){
const
{
teacherQuery
,
teacherList
}
=
this
.
state
;
const
_query
=
{
...
...
@@ -68,6 +69,7 @@ class AddLiveClass extends React.Component {
// 获取助教老师列表
getAssistantList
=
(
current
=
1
,
selectList
)
=>
{
const
{
assistantQuery
,
assistantList
}
=
this
.
state
;
const
_query
=
{
...
assistantQuery
,
current
,
...
...
@@ -134,7 +136,9 @@ class AddLiveClass extends React.Component {
liveDate
,
timeHorizonStart
,
timeHorizonEnd
,
assistant
assistant
,
assistantNames
,
teacherName
}
=
data
;
console
.
log
(
"teacherId"
,
teacherId
);
return
(
...
...
@@ -245,14 +249,17 @@ class AddLiveClass extends React.Component {
<
span
className=
"label"
><
span
className=
"require"
>
*
</
span
>
讲师:
</
span
>
<
Select
placeholder=
"请选择讲师"
// key={teacherName}
// defaultValue={teacherName}
value=
{
teacherId
}
style=
{
{
width
:
240
,
marginTop
:
6
}
}
disabled=
{
!
isEdit
?
true
:
false
}
showSearch
value=
{
teacherId
}
filterOption=
{
(
input
,
option
)
=>
option
}
onPopupScroll=
{
this
.
handleScrollTeacherList
}
onChange=
{
(
value
,
option
)
=>
{
this
.
props
.
onChange
(
'teacherId'
,
value
,
option
.
children
)
console
.
log
(
"value"
,
value
);
this
.
props
.
onChange
(
'teacherId'
,
value
,
option
.
children
)
}
}
onSearch=
{
(
value
)
=>
{
teacherQuery
.
nickName
=
value
...
...
@@ -271,41 +278,46 @@ class AddLiveClass extends React.Component {
}
})
}
</
Select
>
</
div
>
<
div
className=
"assistant-teacher"
>
<
span
className=
"label"
>
助教:
</
span
>
<
Select
id=
"assistant"
placeholder=
"请选择助教老师"
value=
{
assistant
}
disabled=
{
!
isEdit
?
true
:
false
}
mode=
{
'multiple'
}
showSearch
allowClear
style=
{
{
width
:
240
,
marginTop
:
6
}
}
filterOption=
{
(
input
,
option
)
=>
option
}
onPopupScroll=
{
this
.
handleScrollAssistantList
}
onChange=
{
(
value
)
=>
{
this
.
props
.
onChange
(
'assistant'
,
value
)
}
}
onSearch=
{
(
value
)
=>
{
assistantQuery
.
nickName
=
value
this
.
setState
({
assistantQuery
},
()
=>
{
this
.
getAssistantList
()
})
}
}
>
{
_
.
map
(
assistantList
,
(
item
,
index
)
=>
{
if
(
item
.
userId
!==
teacherId
){
return
(
<
Select
.
Option
value=
{
item
.
userId
}
key=
{
item
.
userId
}
>
{
item
.
nickName
}
</
Select
.
Option
>
);
}
})
}
</
Select
>
<
span
className=
"label"
>
助教:
</
span
>
<
Select
id=
"assistant"
placeholder=
"请选择助教老师"
// key={assistantNames}
// defaultValue={assistantNames}
value=
{
assistant
}
disabled=
{
!
isEdit
?
true
:
false
}
mode=
{
'multiple'
}
showSearch
allowClear
style=
{
{
width
:
240
,
marginTop
:
6
}
}
filterOption=
{
(
input
,
option
)
=>
option
}
onPopupScroll=
{
this
.
handleScrollAssistantList
}
onChange=
{
(
value
,
option
)
=>
{
console
.
log
(
'option'
,
option
);
this
.
props
.
onChange
(
'assistant'
,
value
)
}
}
onSearch=
{
(
value
)
=>
{
assistantQuery
.
nickName
=
value
this
.
setState
({
assistantQuery
},
()
=>
{
this
.
getAssistantList
()
})
}
}
>
{
_
.
map
(
assistantList
,
(
item
,
index
)
=>
{
if
(
item
.
userId
!==
teacherId
){
return
(
<
Select
.
Option
value=
{
item
.
userId
}
key=
{
item
.
userId
}
>
{
item
.
nickName
}
</
Select
.
Option
>
);
}
})
}
</
Select
>
</
div
>
</
div
>
</
Spin
>
...
...
src/modules/course-manage/components/AddLiveIntro.jsx
View file @
e926cbc4
...
...
@@ -271,15 +271,15 @@ class AddLiveIntro extends React.Component {
</
div
>
</
div
>
<
div
className=
"allow-tourist-join"
>
<
span
className=
"label"
>
允许游客加入
:
</
span
>
<
span
className=
"label"
>
观看设置
:
</
span
>
<
div
className=
"content"
>
<
div
>
<
Switch
checked=
{
whetherVisitorsJoin
===
"YES"
?
true
:
false
}
onChange=
{
this
.
whetherVisitorsJoinChange
}
/>
</
div
>
<
div
>
<
div
class=
"instro-text"
>
<
div
>
开启:
用户可直接
进入直播间观看直播
</
div
>
<
div
>
关闭:
用户需先填写手机号并短信验证,通过后才可
进入直播间观看直播
</
div
>
<
div
>
开启:
允许未绑定手机号的用户
进入直播间观看直播
</
div
>
<
div
>
关闭:
仅限绑定了手机号的用户可以
进入直播间观看直播
</
div
>
</
div
>
</
div
>
</
div
>
...
...
src/modules/course-manage/components/LiveCourseFilter.jsx
View file @
e926cbc4
...
...
@@ -98,8 +98,10 @@ class LiveCourseFilter extends React.Component {
query
.
endTime
=
dates
[
1
].
valueOf
();
}
this
.
setState
({
query
,
current
:
1
,
query
:{
...
query
,
current
:
1
,
}
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
})
...
...
@@ -124,7 +126,6 @@ class LiveCourseFilter extends React.Component {
handleReset
=
()
=>
{
this
.
setState
({
query
:
{
...
this
.
state
.
query
,
courseName
:
null
,
startTime
:
null
,
endTime
:
null
,
...
...
@@ -132,6 +133,7 @@ class LiveCourseFilter extends React.Component {
teacherName
:
null
,
courseState
:
undefined
,
current
:
1
,
shelfState
:
null
,
},
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
...
...
@@ -172,6 +174,7 @@ class LiveCourseFilter extends React.Component {
format=
{
"YYYY-MM-DD"
}
onChange=
{
(
dates
)
=>
{
this
.
handleChangeDates
(
dates
)
}
}
style=
{
{
width
:
"calc(100% - 70px)"
}
}
/>
</
div
>
<
div
className=
"search-condition__item"
>
...
...
@@ -185,7 +188,7 @@ class LiveCourseFilter extends React.Component {
onPopupScroll=
{
this
.
handleScrollTeacherList
}
value=
{
teacherId
}
onChange=
{
(
value
)
=>
{
this
.
handleChangeQuery
(
'teacherId'
,
value
)
this
.
handleChangeQuery
(
'teacherId'
,
value
)
;
}
}
onSearch=
{
(
value
)
=>
{
teacherQuery
.
nickName
=
value
...
...
@@ -195,6 +198,18 @@ class LiveCourseFilter extends React.Component {
this
.
getTeacherList
()
})
}
}
onClear
={(
value
)=
>
{
this
.
setState
({
teacherQuery
:{
size
:
10
,
current
:
1
,
nickName
:
null
}
},
()
=>
{
this
.
getTeacherList
()
})
}
}
>
{
_
.
map
(
teacherList
,
(
item
,
index
)
=>
{
return
(
...
...
src/modules/course-manage/components/LiveCourseList.jsx
View file @
e926cbc4
This diff is collapsed.
Click to expand it.
src/modules/course-manage/components/LiveCourseList.less
View file @
e926cbc4
...
...
@@ -17,7 +17,7 @@
color: #333333;
line-height: 20px;
font-weight: bold;
max-width:2
38
px;
max-width:2
44
px;
overflow: hidden;
text-overflow:ellipsis;
white-space: nowrap;
...
...
@@ -77,9 +77,11 @@
color: #5289FA;
line-height: 20px;
text-align:right;
cursor:pointer;
}
.quota-icon{
color:#5289FA;
cursor:pointer;
}
.operate {
display: flex;
...
...
@@ -124,8 +126,14 @@
font-size: 12px;
}
}
}
.ant-tooltip{
max-width:700px !important;
}
.ant-tooltip-inner{
max-width:700px !important;
}
.live-course-more-menu {
background: white;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
...
...
src/modules/course-manage/components/LiveCourseOpt.jsx
View file @
e926cbc4
...
...
@@ -8,7 +8,10 @@
import
React
from
'react'
;
import
{
Button
,
Modal
,
message
}
from
'antd'
;
import
Service
from
'@/common/js/service'
;
import
'./liveCourseOpt.less'
;
import
BaseService
from
"@/domains/basic-domain/baseService"
;
import
User
from
'@/common/js/user'
class
LiveCourseOpt
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
...
...
@@ -22,30 +25,30 @@ class LiveCourseOpt extends React.Component {
handleDownloadClient
=
()
=>
{
const
isMac
=
/macintosh|mac os x/i
.
test
(
navigator
.
userAgent
);
// 判断用户系统
if
(
!
isMac
)
{
// axios
// .Apollo("anon/version/getLastedVersion", { model: 1, platform: 1 })
// .then((res) => {
// const a = document.createElement("a");
// document.body.appendChild(a);
// a.href = res.result.releaseUrl;
// a.click();
// document.body.removeChild(a);
// })
}
else
{
Modal
.
info
({
title
:
"抱歉,暂不支持Mac版"
,
content
:
"Mac版正在开发中,敬请期待"
,
icon
:
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>,
okText
:
'我知道了'
});
let
platform
;
if
(
!
isMac
){
platform
=
1
}
else
{
platform
=
4
}
BaseService
.
getLastedVersion
({
model
:
5
,
platform
})
.
then
((
res
)
=>
{
const
a
=
document
.
createElement
(
"a"
);
document
.
body
.
appendChild
(
a
);
a
.
href
=
res
.
result
.
releaseUrl
;
a
.
click
();
document
.
body
.
removeChild
(
a
);
})
}
render
()
{
const
userRole
=
User
.
getUserRole
();
return
(
<
div
className=
"live-course-opt"
>
<
div
className=
"opt__left"
>
<
Button
type=
"primary"
onClick=
{
this
.
handleCreateLiveCouese
}
>
新建直播课
</
Button
>
{
userRole
!==
"CloudLecturer"
&&
<
Button
type=
"primary"
onClick=
{
this
.
handleCreateLiveCouese
}
>
新建直播课
</
Button
>
}
<
Button
onClick=
{
this
.
handleDownloadClient
}
>
下载直播客户端
</
Button
>
</
div
>
</
div
>
...
...
src/modules/course-manage/modal/PreviewCourseModal.jsx
View file @
e926cbc4
...
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Date: 2020-07-23 14:54:16
* @LastEditors: zhangleyuan
* @LastEditTime: 202
0-12-24 10:23:44
* @LastEditTime: 202
1-01-09 16:26:03
* @Description: 大班直播课预览弹窗
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -36,7 +36,16 @@ class PreviewCourseModal extends React.Component {
}
}
dealTimeDuration
=
(
time
)
=>
{
const
diff
=
Math
.
floor
(
time
%
3600
);
let
hours
=
Math
.
floor
(
time
/
3600
);
let
mins
=
Math
.
floor
(
diff
/
60
);
let
seconds
=
Math
.
floor
(
time
%
60
);
hours
=
hours
<
10
?
(
"0"
+
hours
)
:
hours
;
mins
=
mins
<
10
?
(
"0"
+
mins
)
:
mins
;
seconds
=
seconds
<
10
?
(
"0"
+
seconds
)
:
seconds
;
return
hours
+
":"
+
mins
+
":"
+
seconds
;
}
dealWithTime
=
(
startTime
,
endTime
)
=>
{
const
startDate
=
new
Date
(
Number
(
startTime
));
const
endDate
=
new
Date
(
Number
(
endTime
));
...
...
@@ -64,8 +73,8 @@ class PreviewCourseModal extends React.Component {
render
()
{
const
{
courseBasicInfo
,
courseClassInfo
=
{},
courseIntroInfo
,
type
,
courseState
}
=
this
.
props
;
const
{
coverUrl
,
courseName
,
scheduleVideoUrl
}
=
courseBasicInfo
;
const
{
courseBasicInfo
,
courseClassInfo
=
{},
courseIntroInfo
,
type
,
courseState
,
origin
}
=
this
.
props
;
const
{
coverUrl
,
courseName
,
scheduleVideoUrl
,
videoDuration
}
=
courseBasicInfo
;
const
{
liveDate
,
calendarTime
,
startTime
,
endTime
,
timeHorizonStart
,
timeHorizonEnd
,
teacherName
}
=
courseClassInfo
;
const
{
liveCourseMediaRequests
}
=
courseIntroInfo
;
...
...
@@ -128,13 +137,15 @@ class PreviewCourseModal extends React.Component {
<
img
src=
{
coverUrl
}
className=
"course-cover"
/>
}
</
div
>
{
type
===
'videoCourse'
?
<
div
className=
"container__body"
>
<
div
className=
"title__name"
>
{
courseName
}
</
div
>
<
div
className=
"title__inst-name"
>
{
window
.
currentUserInstInfo
.
name
}
</
div
>
</
div
>
:
{
videoDuration
&&
<
div
>
视频时长:
{
this
.
dealTimeDuration
(
videoDuration
)
}
</
div
>
}
</
div
>
:
<
div
className=
"container__body"
>
<
div
className=
"container__body__title"
>
<
div
className=
"title__name"
>
{
courseName
}
</
div
>
...
...
@@ -144,13 +155,11 @@ class PreviewCourseModal extends React.Component {
<
span
className=
"time__label"
>
上课时间:
</
span
>
<
span
className=
"time__value"
>
{
[
<
span
>
{
liveDateStr
}
</
span
>,
<
span
>
{
startTimeStr
}
~
{
endTimeStr
}
</
span
>
]
}
</
span
>
</
div
>
<
div
className=
"container__body__teacher"
>
...
...
@@ -161,7 +170,11 @@ class PreviewCourseModal extends React.Component {
}
<
div
className=
"container__introduction"
>
<
div
className=
"container__introduction__title"
>
直播简介
</
div
>
{
type
===
'videoCourse'
?
<
div
className=
"container__introduction__title"
>
视频简介
</
div
>
:
<
div
className=
"container__introduction__title"
>
直播简介
</
div
>
}
<
div
className=
"container__introduction__list editor-box"
>
{
liveCourseMediaRequests
.
map
((
item
,
index
)
=>
{
...
...
src/modules/course-manage/modal/ShareLiveModal.jsx
View file @
e926cbc4
...
...
@@ -13,6 +13,7 @@ import html2canvas from 'html2canvas';
import
qrcode
from
"@/libs/qrcode/qrcode.js"
;
import
User
from
'@/common/js/user'
;
import
$
from
'jquery'
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
'./ShareLiveModal.less'
;
...
...
@@ -27,7 +28,7 @@ class ShareLiveModal extends React.Component {
shareUrl
:
'https://xiaomai5.com/liveShare?courseId=12'
}
}
componentDidMount
()
{
// 获取短链接
this
.
handleConvertShortUrl
();
...
...
@@ -36,22 +37,22 @@ class ShareLiveModal extends React.Component {
handleConvertShortUrl
=
()
=>
{
const
{
longUrl
}
=
this
.
props
.
data
;
//
//
发请求
// axios.Sales('public/businessShow/convertShortUrls',
{
//
urls: [longUrl]
//
}).then((res) => {
//
const { result = [] } = res;
//
this.setState({
//
shareUrl: result[0].shortUrl
//
}, () => {
//
const qrcodeWrapDom = document.querySelector('#qrcodeWrap');
//
const qrcodeNode = new qrcode({
//
text: this.state.shareUrl,
//
size: 98,
//
})
//
qrcodeWrapDom.appendChild(qrcodeNode);
//
});
//
})
// 发请求
CourseService
.
getQrcode
(
{
urls
:
[
longUrl
]
}).
then
((
res
)
=>
{
const
{
result
=
[]
}
=
res
;
this
.
setState
({
shareUrl
:
result
[
0
].
shortUrl
},
()
=>
{
const
qrcodeWrapDom
=
document
.
querySelector
(
'#qrcodeWrap'
);
const
qrcodeNode
=
new
qrcode
({
text
:
this
.
state
.
shareUrl
,
size
:
98
,
})
qrcodeWrapDom
.
appendChild
(
qrcodeNode
);
});
})
}
componentWillUnmount
()
{
...
...
@@ -87,13 +88,13 @@ class ShareLiveModal extends React.Component {
// 判断是否是默认图, 默认图不需要在URL后面增加字符串
const
isDefaultCover
=
coverUrl
===
DEFAULT_COVER
;
const
coverImgSrc
=
type
===
'videoClass'
// 如果是默认图, 显示视频的第一帧, 否则显示上传的视频封面
?
((
!
coverUrl
||
isDefaultCover
)
?
`
${
scheduleVideoUrl
}
?x-oss-process=video/snapshot,t_0,m_fast&anystring=anystring`
:
`
${
coverUrl
}
${
!
needStr
?
'&anystring=anystring'
:
''
}
`
)
:
`
${
coverUrl
}
${(
!
needStr
&&
!
isDefaultCover
)
?
'&anystring=anystring'
:
''
}
`
:
`
${
coverUrl
}
`
)
:
`
${
coverUrl
}
`
return
(
...
...
@@ -112,10 +113,14 @@ class ShareLiveModal extends React.Component {
</
div
>
<
div
className=
"course-name-title"
>
{
type
===
'videoClass'
?
`${courseName}开课啦`
:
`邀请你观看直播:`
}
</
div
>
<
div
className=
"course-name"
>
{
courseName
}
</
div
>
{
type
===
"liveClass"
&&
<
div
class=
"live-couse-name"
>
{
courseName
}
</
div
>
}
<
img
src=
{
coverImgSrc
}
crossOrigin=
"*"
className=
"course-cover"
/>
...
...
@@ -132,13 +137,26 @@ class ShareLiveModal extends React.Component {
<
div
className=
"right"
>
<
div
className=
"share-poster right__item"
>
<
div
className=
"title"
>
① 海报分享
</
div
>
<
div
className=
"sub-title"
>
学生可通过微信识别二维码,报名观看直播
</
div
>
{
type
===
"liveClass"
&&
<
div
className=
"sub-title"
>
用户可通过微信扫描海报二维码,观看直播
</
div
>
}
{
type
===
"videoClass"
&&
<
div
className=
"sub-title"
>
用户可通过微信识别二维码,报名观看视频
</
div
>
}
<
div
className=
"content"
onClick=
{
this
.
handleDownloadPoster
}
>
下载海报
</
div
>
</
div
>
<
div
className=
"share-url right__item"
>
<
div
className=
"title"
>
② 链接分享
</
div
>
<
div
className=
"sub-title"
>
学生可通过微信打开链接,报名观看直播
</
div
>
{
type
===
"liveClass"
&&
<
div
className=
"sub-title"
>
用户可通过微信打开以下链接,观看直播
</
div
>
}
{
type
===
"videoClass"
&&
<
div
className=
"sub-title"
>
用户可通过打开链接,报名观看视频
</
div
>
}
<
div
className=
"content"
>
<
div
className=
"share-url"
id=
"shareUrl"
>
{
shareUrl
}
</
div
>
<
Button
type=
"primary"
onClick=
{
this
.
handleCopy
}
>
复制
</
Button
>
...
...
src/modules/course-manage/modal/ShareLiveModal.less
View file @
e926cbc4
...
...
@@ -14,6 +14,11 @@
line-height: 20px;
margin-bottom: 4px;
}
.live-couse-name{
font-size:16px;
color:#333333;
font-weight: 600;
}
.course-name {
color: #333;
font-size: 16px;
...
...
src/modules/course-manage/video-course/AddVideoCourse.jsx
0 → 100644
View file @
e926cbc4
This diff is collapsed.
Click to expand it.
src/modules/course-manage/video-course/AddVideoCourse.less
0 → 100644
View file @
e926cbc4
.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-catalog{
margin-bottom:16px;
margin-top:16px;
}
.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/AddVideoIntro.jsx
0 → 100644
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Last Modified by: mikey.zhaopeng
* @Last Modified time: 2020-11-24 14:29:52
* @Description: 添加直播-简介
*/
import
React
from
'react'
;
import
{
Input
,
message
,
Upload
,
Radio
,
Row
,
Col
,
Button
,
Popover
,
Switch
}
from
'antd'
;
import
Service
from
'@/common/js/service'
;
import
EditorBox
from
'../../components/EditorBox'
;
import
User
from
'@/common/js/user'
;
import
UploadOss
from
'@/core/upload'
;
import
'./AddVideoIntro.less'
;
import
SelectPrepareFileModal
from
'@/modules/prepare-lesson/modal/SelectPrepareFileModal'
;
import
{
DISK_MAP
}
from
'@/common/constants/academic/lessonEnum'
;
import
{
ImgCutModalNew
}
from
'@/components'
;
const
{
TextArea
}
=
Input
;
const
defaultCover
=
'https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1599635741526.png'
;
class
AddVideoIntro
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
warmUrl
:
defaultCover
,
showSelectFileModal
:
false
,
diskList
:
[],
selectType
:
null
}
}
// 上传封面图
handleShowImgCutModal
=
(
event
)
=>
{
const
imageFile
=
event
.
target
.
files
[
0
];
if
(
!
imageFile
)
return
;
this
.
setState
({
imageFile
,
showCutModal
:
true
,
});
}
// 选择暖场资源
handleSelectVideo
=
(
file
)
=>
{
const
{
selectType
}
=
this
.
state
;
this
.
setState
({
showSelectFileModal
:
false
})
const
{
ossUrl
,
resourceId
,
folderName
,
folderFormat
,
folderSize
}
=
file
;
if
(
selectType
===
'WARMUP'
){
const
liveCourseWarmMedia
=
{
contentType
:
'WARMUP'
,
mediaType
:
folderFormat
===
'MP4'
?
'VIDEO'
:
'PICTURE'
,
mediaContent
:
resourceId
,
mediaUrl
:
ossUrl
,
mediaName
:
folderName
,
size
:
folderSize
}
this
.
props
.
onChange
(
'liveCourseWarmMedia'
,
liveCourseWarmMedia
);
}
else
{
// 最多添加九图片
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
const
list
=
_
.
filter
(
liveCourseMediaRequests
,
(
item
)
=>
{
return
item
.
mediaType
==
"PICTURE"
;
});
if
(
list
.
length
>
8
)
{
message
.
warning
(
"最多添加9张图片"
);
return
;
}
liveCourseMediaRequests
.
push
({
contentType
:
'INTRO'
,
size
:
folderSize
,
mediaName
:
folderName
,
mediaContent
:
resourceId
,
mediaType
:
'PICTURE'
,
mediaUrl
:
ossUrl
,
});
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
}
// 删除简介
handleDeleteIntro
=
(
index
)
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
liveCourseMediaRequests
.
splice
(
index
,
1
);
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
// 上移简介
handleMoveUpIntro
=
(
index
)
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
const
prevItem
=
liveCourseMediaRequests
[
index
];
const
nextItem
=
liveCourseMediaRequests
[
index
+
1
];
liveCourseMediaRequests
.
splice
(
index
,
2
,
nextItem
,
prevItem
);
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
// 下移简介
handleMoveDownIntro
=
(
index
)
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
const
prevItem
=
liveCourseMediaRequests
[
index
-
1
];
const
nextItem
=
liveCourseMediaRequests
[
index
];
liveCourseMediaRequests
.
splice
(
index
-
1
,
2
,
nextItem
,
prevItem
);
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
renderLittleIcon
=
(
index
)
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
return
(
<
div
className=
"little-icon"
>
<
span
className=
"icon iconfont close"
onClick=
{
()
=>
{
this
.
handleDeleteIntro
(
index
);
}
}
></
span
>
{
index
>
0
&&
<
span
className=
"icon iconfont"
onClick=
{
()
=>
{
this
.
handleMoveDownIntro
(
index
);
}
}
>

</
span
>
}
{
index
!==
liveCourseMediaRequests
.
length
-
1
&&
<
span
className=
"icon iconfont"
onClick=
{
()
=>
{
this
.
handleMoveUpIntro
(
index
);
}
}
>

</
span
>
}
</
div
>
)
}
handleChangeIntro
=
(
index
,
value
,
length
)
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
liveCourseMediaRequests
[
index
].
mediaContent
=
value
;
liveCourseMediaRequests
[
index
].
mediaContentLength
=
length
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
handleAddIntroText
=
()
=>
{
const
{
liveCourseMediaRequests
}
=
this
.
props
.
data
;
liveCourseMediaRequests
.
push
({
contentType
:
"INTRO"
,
mediaType
:
'TEXT'
,
mediaContent
:
''
,
key
:
Math
.
random
()
});
this
.
props
.
onChange
(
'liveCourseMediaRequests'
,
liveCourseMediaRequests
);
}
handleUpload
=
(
Blob
)
=>
{
this
.
setState
({
showSelectFileModal
:
true
,
selectType
:
'INTRO'
})
}
whetherVisitorsJoinChange
=
()
=>
{
if
(
this
.
props
.
data
.
whetherVisitorsJoin
===
"NO"
){
this
.
props
.
onChange
(
'whetherVisitorsJoin'
,
'YES'
)
}
else
{
this
.
props
.
onChange
(
'whetherVisitorsJoin'
,
'NO'
)
}
}
shelfStateChange
=
()
=>
{
if
(
this
.
props
.
data
.
shelfState
===
"NO"
){
this
.
props
.
onChange
(
'shelfState'
,
'YES'
)
}
else
{
this
.
props
.
onChange
(
'shelfState'
,
'NO'
)
}
}
componentWillMount
()
{
}
render
()
{
const
{
data
:
{
whetherVisitorsJoin
,
liveCourseMediaRequests
=
[],
shelfState
}
}
=
this
.
props
;
const
{
showSelectFileModal
,
selectType
}
=
this
.
state
return
(
<
div
className=
"add-video__intro-info"
>
<
div
className=
"allow-tourist-join"
>
<
span
className=
"label"
>
观看设置:
</
span
>
<
div
className=
"content"
>
<
Row
>
<
Col
span=
{
3
}
>
<
Switch
checked=
{
whetherVisitorsJoin
===
"YES"
?
true
:
false
}
onChange=
{
this
.
whetherVisitorsJoinChange
}
/>
</
Col
>
<
Col
span=
{
21
}
>
<
div
className=
"desc"
>
<
div
>
开启:允许未绑定手机号的用户进入直播间观看直播
</
div
>
<
div
>
关闭:仅限绑定了手机号的用户可以进入直播间观看直播
</
div
>
</
div
>
</
Col
>
</
Row
>
</
div
>
</
div
>
<
div
className=
"store-show"
>
<
span
className=
"label"
>
店铺展示:
</
span
>
<
div
className=
"content"
>
<
Row
>
<
Col
span=
{
3
}
>
<
Switch
checked=
{
shelfState
===
"YES"
?
true
:
false
}
onChange=
{
this
.
shelfStateChange
}
/>
</
Col
>
<
Col
span=
{
21
}
>
<
div
className=
"desc"
>
<
div
>
开启:此视频将在用户店铺的视频列表中出现
</
div
>
<
div
>
关闭:此视频将在用户店铺的视频列表中隐藏
</
div
>
</
div
>
</
Col
>
</
Row
>
</
div
>
</
div
>
<
div
className=
"introduce"
>
<
span
className=
"label"
>
视频课简介:
</
span
>
<
div
className=
"content"
>
<
div
className=
"intro-list"
>
{
liveCourseMediaRequests
.
map
((
item
,
index
)
=>
{
if
(
item
.
mediaType
===
'TEXT'
)
{
return
(
<
div
className=
"intro-list__item"
key=
{
item
.
key
}
>
<
EditorBox
detail=
{
{
content
:
item
.
mediaContent
}
}
onChange=
{
(
val
,
length
)
=>
{
this
.
handleChangeIntro
(
index
,
val
,
length
)
}
}
/>
{
this
.
renderLittleIcon
(
index
)
}
</
div
>
)
}
if
(
item
.
mediaType
===
'PICTURE'
)
{
return
(
<
div
className=
"intro-list__item picture"
key=
{
index
}
>
<
div
className=
"img__wrap"
>
<
img
src=
{
item
.
mediaUrl
}
/>
</
div
>
{
this
.
renderLittleIcon
(
index
)
}
</
div
>
)
}
})
}
</
div
>
<
div
className=
"operate"
>
<
div
className=
"operate__item"
onClick=
{
this
.
handleAddIntroText
}
>
<
span
className=
"icon iconfont"
>

</
span
>
<
span
className=
"text"
>
文字
</
span
>
</
div
>
<
div
className=
"operate__item"
onClick=
{
this
.
handleUpload
}
>
<
span
className=
"icon iconfont"
>

</
span
>
<
span
className=
"text"
>
图片
</
span
>
</
div
>
</
div
>
<
div
className=
"tips"
>
• 图片支持jpeg、jpg、png、gif格式
</
div
>
</
div
>
</
div
>
{
/* 选择暖场图文件弹窗 */
}
<
SelectPrepareFileModal
operateType=
"select"
accept=
{
selectType
===
"INTRO"
?
"image/jpeg,image/png,image/jpg"
:
"video/mp4,image/jpeg,image/png,image/jpg"
}
selectTypeList=
{
selectType
===
"INTRO"
?
[
'JPG'
,
'JPEG'
,
'PNG'
]:
[
'MP4'
,
'JPG'
,
'JPEG'
,
'PNG'
]
}
tooltip=
{
selectType
===
"INTRO"
?
'支持文件类型:jpg、jpeg、png'
:
'支持文件类型:jpg、jpeg、png、mp4'
}
isOpen=
{
showSelectFileModal
}
onClose=
{
()
=>
{
this
.
setState
({
showSelectFileModal
:
false
})
}
}
onSelect=
{
this
.
handleSelectVideo
}
/>
</
div
>
)
}
}
export
default
AddVideoIntro
;
src/modules/course-manage/video-course/components/AddVideoIntro.less
0 → 100644
View file @
e926cbc4
.add-video__intro-info {
.playback {
margin-bottom: 10px;
.require {
color: #EC4B35;
}
&__text {
color: #999;
}
}
.playback,
.introduce {
display: flex;
flex-direction: row;
}
.allow-tourist-join{
display:flex;
.desc{
margin-left:16px;
font-size:14px;
color:#999;
}
}
.store-show{
display:flex;
margin-top:16px;
margin-bottom:16px;
.desc{
margin-left:16px;
font-size:14px;
color:#999;
}
}
.radio {
display: block;
height: 30px;
line-height: 30px;
}
.interactive-playback {
display: flex;
margin-bottom: 20px;
}
textarea.ant-input {
min-height: 80px;
}
.intro-list__item {
display: flex;
margin-bottom: 16px;
position: relative;
&.picture {
width: 550px;
padding: 16px;
border: 1px solid #EEE;
border-radius: 4px;
.img__wrap {
width: 299px;
height: 168px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
}
.little-icon {
display: flex;
flex-direction: column;
position: absolute;
top: 0;
right: -20px;
.iconfont {
width: 20px;
height: 20px;
line-height: 20px;
font-size: 20px;
color: #999;
margin-bottom: 4px;
cursor: pointer;
&.close {
margin-top: 8px;
background-image: url('https://image.xiaomaiketang.com/xm/eesMPhNP3e.png');
background-size: 100% 100%;
}
}
}
}
.operate {
display: flex;
align-items: center;
justify-content: center;
width: 550px;
height: 80px;
line-height: 80px;
padding: 16px;
margin-top: 16px;
border: 1px dashed #EBEBEB;
border-radius: 4px;
.ant-upload {
vertical-align: middle;
}
&__item {
display: flex;
flex-direction: column;
cursor: pointer;
&:not(:last-child) {
margin-right: 82px;
}
.iconfont {
font-size: 22px;
line-height: 22px;
color: #BFBFBF;
text-align: center;
}
.text {
color: #999;
line-height: 20px;
margin-top: 4px;
}
}
}
.tips {
color: #999;
margin-top: 16px;
margin-bottom: 8px;
}
.checkExample {
width: 60px;
color: #FF7519;
cursor: pointer;
}
.warmup {
margin-bottom: 17px;
display: flex;
}
.course-cover__wrap {
display: flex;
flex-direction: row;
}
.img-content {
position: relative;
margin-right: 20px;
width: 300px;
height: 170px;
img {
width: 100%;
height: 100%;
object-fit: contain;
}
.img-delete-wrap {
opacity: 0;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
img {
position: absolute;
left: 50%;
top: 50%;
width: 40px;
height: 40px;
transform: translate(-50%, -50%);
}
&:hover {
opacity: 1;
cursor: pointer;
}
}
}
.opt-btns {
.default-btn {
margin-left: 16px;
color: #FF7519;
cursor: pointer;
&.disabled {
color: #CCC;
cursor: not-allowed;
}
}
}
}
.example-wrap {
font-family: PingFangSC-Regular, PingFang SC;
text-align: center;
.title {
margin-bottom: 6px;
font-size: 14px;
color: #333333;
}
.text {
margin-bottom: 16px;
font-size: 12px;
color: #999999;
}
img {
width: 180px;
}
}
.check-record-rule {
width: 120px;
color: #FF7519;
cursor: pointer;
z-index: 2;
}
.record-rule-wrap {
text-align: left;
ul {
margin-top: 10px;
padding-left: 34px;
list-style-type: disc;
li {
color: #999;
}
}
.text {
color: #999;
}
}
.auto-send-class-report {
.label {
width: 57px;
height: 12px;
font-size: 14px;
font-weight: 400;
color: #666666;
line-height: 12px;
}
.open-text, .close-text {
width: 572px;
font-size: 14px;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-left: 100px;
margin-top: 5px;
}
.open-text {
margin-top: 8px;
}
.close-text {
margin-bottom: 16px;
}
}
\ No newline at end of file
src/modules/course-manage/video-course/components/VideoCourseFilter.jsx
0 → 100644
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:11:57
* @LastEditors: zhangleyuan
* @LastEditTime: 2021-01-15 13:52:10
* @Description: 视频课-搜索模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Row
,
Input
,
Select
,
Tooltip
}
from
'antd'
;
import
RangePicker
from
"@/modules/common/DateRangePicker"
;
// import TeacherSelectV5 from '@/modules/classManage_V5/classDetail/TeacherSelectV5';
import
'./VideoCourseFilter.less'
;
import
moment
from
'moment'
;
import
StoreService
from
"@/domains/store-domain/storeService"
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
const
DEFAULT_QUERY
=
{
courseName
:
null
,
// 课程名称
operatorId
:
null
,
// 创建人
beginTime
:
null
,
// 开始日期
endTime
:
null
,
// 结束日期
shelfState
:
null
,
}
const
defaultTeacherQuery
=
{
size
:
10
,
current
:
1
,
nickName
:
null
}
class
VideoCourseFilter
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
query
:
{
...
DEFAULT_QUERY
},
// 使用扩展运算符,避免浅拷贝
teacherQuery
:
defaultTeacherQuery
,
teacherList
:[],
expandFilter
:
false
}
}
componentDidMount
()
{
this
.
getTeacherList
();
}
getTeacherList
(
current
=
1
,
selectList
){
const
{
teacherQuery
,
teacherList
}
=
this
.
state
;
const
_query
=
{
...
teacherQuery
,
current
,
size
:
10
};
StoreService
.
getStoreUserBasicPage
(
_query
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
,
hasNext
}
=
result
;
const
list
=
current
>
1
?
teacherList
.
concat
(
records
)
:
records
;
this
.
setState
({
hasNext
,
teacherList
:
list
,
})
});
}
// 滑动加载更多讲师列表
handleScrollTeacherList
=
(
e
)
=>
{
const
{
hasNext
}
=
this
.
state
;
const
container
=
e
.
target
;
const
scrollToBottom
=
container
&&
container
.
scrollHeight
<=
container
.
clientHeight
+
container
.
scrollTop
;
if
(
scrollToBottom
&&
hasNext
)
{
const
{
teacherQuery
}
=
this
.
state
;
this
.
getTeacherList
(
teacherQuery
.
current
+
1
);
}
}
// 改变搜索条件
handleChangeQuery
=
(
field
,
value
)
=>
{
this
.
setState
({
query
:
{
...
this
.
state
.
query
,
[
field
]:
value
,
current
:
1
,
}
},
()
=>
{
if
(
field
===
'courseName'
)
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
:{
...
query
,
current
:
1
,
}
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
})
}
// 重置搜索条件
handleReset
=
()
=>
{
this
.
setState
({
query
:
DEFAULT_QUERY
,
},
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
);
})
}
render
()
{
const
{
query
:
{
courseName
,
operator
,
beginTime
,
endTime
,
operatorId
,
shelfState
},
expandFilter
,
teacherList
,
teacherQuery
}
=
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=
{
courseName
}
placeholder=
"搜索视频课名称"
onChange=
{
(
e
)
=>
{
this
.
handleChangeQuery
(
'courseName'
,
e
.
target
.
value
)}
}
onSearch=
{
()
=>
{
this
.
props
.
onChange
(
this
.
state
.
query
)
}
}
style=
{
{
width
:
"calc(100% - 84px)"
}
}
/>
</
div
>
<
div
className=
"search-condition__item"
>
<
span
>
创建人:
</
span
>
<
Select
placeholder=
"请选择创建人"
style=
{
{
width
:
"calc(100% - 70px)"
}
}
showSearch
allowClear
filterOption=
{
(
input
,
option
)
=>
option
}
onPopupScroll=
{
this
.
handleScrollTeacherList
}
value=
{
operatorId
}
onChange=
{
(
value
)
=>
{
this
.
handleChangeQuery
(
'operatorId'
,
value
)
}
}
onSearch=
{
(
value
)
=>
{
teacherQuery
.
nickName
=
value
this
.
setState
({
teacherQuery
},
()
=>
{
this
.
getTeacherList
()
})
}
}
onClear
={(
value
)=
>
{
this
.
setState
({
teacherQuery
:{
size
:
10
,
current
:
1
,
nickName
:
null
}
},
()
=>
{
this
.
getTeacherList
()
})
}
}
>
{
_
.
map
(
teacherList
,
(
item
,
index
)
=>
{
return
(
<
Select
.
Option
value=
{
item
.
id
}
key=
{
item
.
id
}
>
{
item
.
nickName
}
</
Select
.
Option
>
);
})
}
</
Select
>
{
/* <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
>
{
expandFilter
&&
<
div
className=
"search-condition__item"
>
<
span
className=
"shelf-status"
>
店铺展示:
</
span
>
<
Select
style=
{
{
width
:
"calc(100% - 84px)"
}
}
placeholder=
"请选择"
allowClear=
{
true
}
value=
{
shelfState
}
onChange=
{
(
value
)
=>
{
this
.
handleChangeQuery
(
'shelfState'
,
value
)
}
}
>
<
Option
value=
"YES"
>
开启
</
Option
>
<
Option
value=
"NO"
>
关闭
</
Option
>
</
Select
>
</
div
>
}
</
div
>
<
div
className=
"reset-fold-area"
>
<
Tooltip
title=
"清空筛选"
><
span
className=
"resetBtn iconfont icon"
onClick=
{
this
.
handleReset
}
>

</
span
></
Tooltip
>
<
span
style=
{
{
cursor
:
'pointer'
}
}
className=
"fold-btn"
onClick=
{
()
=>
{
this
.
setState
({
expandFilter
:
!
expandFilter
});
}
}
>
{
this
.
state
.
expandFilter
?
<
span
><
span
>
收起
</
span
><
span
className=
"iconfont icon fold-icon"
>

</
span
>
</
span
>
:
<
span
>
展开
<
span
className=
"iconfont icon fold-icon"
>

</
span
></
span
>
}
</
span
>
</
div
>
</
Row
>
</
div
>
)
}
}
export
default
VideoCourseFilter
;
src/modules/course-manage/video-course/components/VideoCourseFilter.less
0 → 100644
View file @
e926cbc4
.video-course-filter {
position: relative;
.search-condition {
width: calc(100% - 80px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 30%;
margin-right: 3%;
margin-bottom: 12px;
.search-name{
vertical-align: middle;
}
.shelf-status{
width:84px;
display:inline-block;
text-align:right;
}
}
}
.reset-fold-area {
position: absolute;
right: 12px;
}
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
.fold-btn {
font-size: 14px;
color: #666666;
line-height: 20px;
.fold-icon {
font-size: 12px;
}
}
}
.data-icon {
cursor: pointer;
}
src/modules/course-manage/video-course/components/VideoCourseList.jsx
0 → 100644
View file @
e926cbc4
This diff is collapsed.
Click to expand it.
src/modules/course-manage/video-course/components/VideoCourseList.less
0 → 100644
View file @
e926cbc4
.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;
width:188px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height:48px;
}
}
}
.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;
}
}
}
.ant-tooltip{
max-width:700px !important;
}
.ant-tooltip-inner{
max-width:700px !important;
}
\ No newline at end of file
src/modules/course-manage/video-course/components/VideoCourseOpt.less
0 → 100644
View file @
e926cbc4
.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 @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:15
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 16:07:27
* @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
>
</
div
>
);
}
src/modules/course-manage/video-course/index.jsx
0 → 100644
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:08:06
* @LastEditors: zhangleyuan
* @LastEditTime: 2020-12-26 15:56:49
* @Description: 云课堂-视频课入口页面
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
VideoCourseFilter
from
'./components/VideoCourseFilter'
;
import
VideoCourseOpt
from
'./components/VieoCourseOpt'
;
import
VideoCourseList
from
'./components/VideoCourseList'
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
User
from
'@/common/js/user'
class
VideoCourse
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
query
:
{
size
:
10
,
current
:
1
,
storeId
:
User
.
getStoreId
()
},
dataSource
:
[],
// 视频课列表
totalCount
:
0
,
// 视频课数据总条数
}
}
componentWillMount
()
{
// 获取视频课列表
this
.
handleFetchScheduleList
();
}
// 获取视频课列表
handleFetchScheduleList
=
(
_query
=
{})
=>
{
const
query
=
{
...
this
.
state
.
query
,
...
_query
};
// 更新请求参数
this
.
setState
({
query
});
CourseService
.
videoSchedulePage
(
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/WatchDataModal.jsx
0 → 100644
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-05-19 11:01:31
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-05-25 16:50:47
* @Description 余额异常弹窗
*/
import
React
from
'react'
;
import
{
Table
,
Modal
,
Input
}
from
'antd'
;
import
{
PageControl
}
from
"@/components"
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
User
from
'@/common/js/user'
import
'./WatchDataModal.less'
;
import
dealTimeDuration
from
"../../utils/dealTimeDuration"
;
const
{
Search
}
=
Input
;
class
WatchDataModal
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
visible
:
true
,
dataSource
:[],
size
:
10
,
query
:
{
current
:
1
,
},
totalCount
:
0
};
}
componentDidMount
()
{
this
.
handleFetchDataList
();
}
onClose
=
()
=>
{
this
.
props
.
close
();
}
// 获取观看视频数据列表
handleFetchDataList
=
()
=>
{
const
{
query
,
size
,
totalCount
}
=
this
.
state
const
{
id
}
=
this
.
props
.
data
;
const
params
=
{
...
query
,
size
,
courseId
:
id
,
storeId
:
User
.
getStoreId
()
}
CourseService
.
videoWatchInfo
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
dataSource
:
records
,
totalCount
:
Number
(
total
)
});
});
}
handleChangNickname
=
(
value
)
=>
{
const
isPhone
=
(
value
||
''
).
match
(
/^
\d
+$/
);
const
{
query
}
=
this
.
state
;
if
(
isPhone
){
query
.
phone
=
value
;
query
.
nickName
=
null
;
}
else
{
query
.
nickName
=
value
;
query
.
phone
=
null
;
}
query
.
current
=
1
;
this
.
setState
({
query
})
}
onShowSizeChange
=
(
current
,
size
)
=>
{
if
(
current
==
size
)
{
return
}
this
.
setState
({
size
},()
=>
{
this
.
handleFetchDataList
()})
}
// 请求表头
parseColumns
=
()
=>
{
const
columns
=
[
{
title
:
'观看用户'
,
key
:
'name'
,
dataIndex
:
'name'
},
{
title
:
'手机号'
,
key
:
'phone'
,
dataIndex
:
'phone'
},
{
title
:
'观看者类型'
,
key
:
'userRole'
,
dataIndex
:
'userRole'
},
{
title
:
'首次观看时间'
,
key
:
'firstWatch'
,
dataIndex
:
'firstWatch'
,
render
:
(
val
)
=>
{
return
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
},
{
title
:
'观看时长'
,
key
:
'watchDuration'
,
dataIndex
:
'watchDuration'
,
render
:
(
val
)
=>
{
return
<
span
>
{
val
?
dealTimeDuration
(
val
)
:
"00:00:00"
}
</
span
>
}
}
];
return
columns
;
}
render
()
{
const
{
visible
,
size
,
dataSource
,
totalCount
,
query
,
current
}
=
this
.
state
;
return
(
<
Modal
title=
"视频课观看数据"
visible=
{
visible
}
footer=
{
null
}
onCancel=
{
this
.
onClose
}
maskClosable=
{
false
}
className=
"watch-data-modal"
closable=
{
true
}
width=
{
720
}
>
<
div
className=
"search-container"
>
<
Search
placeholder=
"搜索用户姓名/手机号"
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangNickname
(
e
.
target
.
value
)}
}
onSearch=
{
()
=>
{
this
.
handleFetchDataList
()}
}
/>
</
div
>
<
div
>
<
Table
rowKey=
{
record
=>
record
.
id
}
dataSource=
{
dataSource
}
columns=
{
this
.
parseColumns
()
}
pagination=
{
false
}
/>
{
dataSource
.
length
>
0
&&
<
div
className=
"box-footer"
>
<
PageControl
current=
{
current
-
1
}
pageSize=
{
size
}
total=
{
totalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{...
query
,
current
:
page
+
1
};
this
.
setState
({
query
:
_query
},()
=>
{
this
.
handleFetchDataList
()})
}
}
onShowSizeChange=
{
this
.
onShowSizeChange
}
/>
</
div
>
}
</
div
>
</
Modal
>
)
}
}
export
default
WatchDataModal
;
\ No newline at end of file
src/modules/course-manage/video-course/modal/WatchDataModal.less
0 → 100644
View file @
e926cbc4
.watch-data-modal{
.search-container{
text-align:right;
margin-bottom:17px;
}
}
\ No newline at end of file
src/modules/root/Header.tsx
View file @
e926cbc4
...
...
@@ -94,7 +94,7 @@ function Header(props:headerProps){
<
div
>
<
img
src=
{
logoImg
}
className=
"logo"
alt=
""
/>
{
menuType
&&
(
<
span
className=
"logo-name"
>
小麦
云课堂
</
span
>
<
span
className=
"logo-name"
>
小麦
企培
</
span
>
)
}
</
div
>
{
menuType
?
(
...
...
src/modules/root/Login.jsx
View file @
e926cbc4
...
...
@@ -113,7 +113,7 @@ function Login(props) {
<
div
className=
"login-main"
>
<
div
className=
"left-banner"
>
<
div
><
img
src=
{
require
(
"../../common/images/logo.png"
)
}
alt=
""
style=
{
{
width
:
60
,
height
:
61
}
}
/></
div
>
<
div
className=
"name"
>
小麦
云课堂
</
div
>
<
div
className=
"name"
>
小麦
企培
</
div
>
<
div
className=
"desc"
>
一键开启直播授课 让知识更有价值
</
div
>
</
div
>
<
div
className=
"login-box"
>
...
...
src/routes/config/mainRoutes.tsx
View file @
e926cbc4
/*
* @Author: 吴文洁
* @Date: 2020-04-29 10:26:32
* @LastEditors:
wuf
an
* @LastEditTime: 202
0-12-26 14:44:41
* @LastEditors:
zhangleyu
an
* @LastEditTime: 202
1-01-15 20:32:56
* @Description: 内容线路由配置
*/
import
EmployeesManagePage
from
'@/modules/store-manage/EmployeesManagePage'
;
...
...
@@ -12,6 +12,10 @@ 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'
;
import
ResourceDisk
from
'@/modules/resource-disk'
;
import
SwitchRoute
from
'@/modules/root/SwitchRoute'
;
...
...
@@ -44,7 +48,12 @@ const mainRoutes = [
{
path
:
'/live-course'
,
component
:
LiveCoursePage
,
name
:
'课程管理'
name
:
'直播课'
},
{
path
:
'/video-course'
,
component
:
VideoCoursePage
,
name
:
'视频课'
},
{
path
:
'/create-live-course'
,
...
...
@@ -52,6 +61,11 @@ const mainRoutes = [
name
:
'创建直播课'
},
{
path
:
'/create-video-course'
,
component
:
AddVideoCoursePage
,
name
:
'创建视频课'
},
{
path
:
'/resource-disk'
,
component
:
ResourceDisk
,
name
:
'资料云盘'
...
...
src/routes/config/menuList.tsx
View file @
e926cbc4
...
...
@@ -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