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
b427be83
Commit
b427be83
authored
Sep 03, 2021
by
wufan
Browse files
Options
Browse Files
Download
Plain Diff
fix:解决冲突
parents
f17356af
8dd6143a
Hide whitespace changes
Inline
Side-by-side
Showing
84 changed files
with
10345 additions
and
1495 deletions
+10345
-1495
src/common/js/user.ts
+24
-17
src/common/less/icon-font.less
+3
-3
src/components/RichText.jsx
+21
-0
src/components/WWOpenData.jsx
+0
-2
src/components/XMTable.jsx
+13
-9
src/core/antd.less
+1
-0
src/core/global.less
+34
-15
src/core/page.less
+1
-1
src/data-source/taskCenter/request-apis.ts
+66
-0
src/domains/basic-domain/constants.ts
+2
-2
src/domains/course-domain/constants.ts
+2
-2
src/domains/task-center-domain/TaskCenterService.ts
+97
-0
src/h5.html
+3
-3
src/index.d.ts
+11
-1
src/index.html
+6
-6
src/modules/college-manage/EmployeeManage.tsx
+232
-198
src/modules/college-manage/modal/SetEmployeeModal.jsx
+0
-7
src/modules/course-manage/components/GraphicsEditor.jsx
+3
-2
src/modules/course-manage/components/LiveCourseList.jsx
+141
-141
src/modules/course-manage/graphics-course/components/GraphicsCourseList.jsx
+455
-480
src/modules/course-manage/modal/RelatedPlanModal.jsx
+45
-28
src/modules/course-manage/modal/RelatedPlanModal.less
+128
-119
src/modules/course-manage/video-course/components/VideoCourseList.jsx
+116
-116
src/modules/home/Home.jsx
+80
-80
src/modules/home/Home.less
+6
-5
src/modules/knowledge-base/components/KnowledgeBaseList.jsx
+2
-2
src/modules/knowledge-base/modal/VideoList.jsx
+1
-1
src/modules/plan-manage/components/BasicInfo.jsx
+12
-4
src/modules/plan-manage/modal/SharePlanModal.jsx
+41
-41
src/modules/resource-disk/components/FolderList.jsx
+2
-0
src/modules/root/Header.jsx
+5
-4
src/modules/store-manage/EmployeeAddOrEditModal.tsx
+105
-150
src/modules/task-center/data-center/Index.tsx
+97
-0
src/modules/task-center/data-center/UserLearningData.jsx
+82
-0
src/modules/task-center/data-center/UserLearningData.less
+62
-0
src/modules/task-center/data-center/components/CourseTable.tsx
+77
-0
src/modules/task-center/data-center/components/CustomerLearnBasicInfo.jsx
+41
-0
src/modules/task-center/data-center/components/DataAnalysic.tsx
+63
-0
src/modules/task-center/data-center/components/DataInfo.tsx
+65
-0
src/modules/task-center/data-center/components/ExamData.tsx
+321
-0
src/modules/task-center/data-center/components/ExamTable.tsx
+137
-0
src/modules/task-center/data-center/components/LeftStageList.jsx
+72
-0
src/modules/task-center/data-center/components/LeftStageList.less
+49
-0
src/modules/task-center/data-center/components/StudyTable.tsx
+351
-0
src/modules/task-center/data-center/components/TestLinkTaskData.jsx
+116
-0
src/modules/task-center/data-center/components/TestLinkTaskData.less
+115
-0
src/modules/task-center/data-center/components/UserData.tsx
+428
-0
src/modules/task-center/data-center/components/WholeData.jsx
+108
-0
src/modules/task-center/data-center/components/WholeData.less
+62
-0
src/modules/task-center/data-center/components/course.less
+112
-0
src/modules/task-center/data-center/components/dataAnalysic.less
+22
-0
src/modules/task-center/data-center/components/study.less
+4
-0
src/modules/task-center/data-center/components/userData.less
+90
-0
src/modules/task-center/data-center/index.less
+122
-0
src/modules/task-center/enum.ts
+95
-0
src/modules/task-center/train-task/AddTrainTask.jsx
+505
-0
src/modules/task-center/train-task/AddTrainTask.less
+83
-0
src/modules/task-center/train-task/TrainTaskPage.jsx
+100
-0
src/modules/task-center/train-task/components/BasicInfo.jsx
+441
-0
src/modules/task-center/train-task/components/BasicInfo.less
+121
-0
src/modules/task-center/train-task/components/ExpiredCourseList.jsx
+92
-0
src/modules/task-center/train-task/components/ExpiredCourseList.less
+64
-0
src/modules/task-center/train-task/components/RelatedCourseDrawer.jsx
+911
-0
src/modules/task-center/train-task/components/RelatedCourseDrawer.less
+105
-0
src/modules/task-center/train-task/components/RelatedExamDrawer.jsx
+335
-0
src/modules/task-center/train-task/components/RelatedExamDrawer.less
+76
-0
src/modules/task-center/train-task/components/TrainContent.jsx
+569
-0
src/modules/task-center/train-task/components/TrainContent.less
+204
-0
src/modules/task-center/train-task/components/TrainFilter.jsx
+171
-0
src/modules/task-center/train-task/components/TrainFilter.less
+23
-0
src/modules/task-center/train-task/components/TrainList.jsx
+491
-0
src/modules/task-center/train-task/components/TrainList.less
+139
-0
src/modules/task-center/train-task/modal/ChooseAssignorModal.jsx
+522
-0
src/modules/task-center/train-task/modal/ChooseAssignorModal.less
+179
-0
src/modules/task-center/train-task/modal/ChooseCollaboratorModal.jsx
+258
-0
src/modules/task-center/train-task/modal/ChooseCollaboratorModal.less
+107
-0
src/modules/task-center/train-task/modal/ShareTrainTaskModal.jsx
+192
-0
src/modules/task-center/train-task/modal/ShareTrainTaskModal.less
+218
-0
src/modules/teach-tool/components/CourseCategoryManage.jsx
+2
-2
src/modules/teach-tool/examination-manager/SelectPaperModal.tsx
+34
-28
src/modules/teach-tool/examination-manager/TestDetailPage.jsx
+10
-4
src/modules/teach-tool/examination-manager/TestDetailPage.less
+9
-0
src/routes/config/mainRoutes.tsx
+29
-17
src/routes/config/menuList.tsx
+6
-5
No files found.
src/common/js/user.ts
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-08-31 09:34:25
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
7-20 17:21:16
* @LastEditors:
yuananting
* @LastEditTime: 2021-0
8-17 19:20:33
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
Storage
from
'./storage'
;
import
{
PREFIX
,
USER_PREFIX
}
from
'@/domains/basic-domain/constants'
;
declare
var
window
:
any
;
declare
var
window
:
any
;
class
User
{
getExpirationTime
()
{
return
Storage
.
get
(
`
${
PREFIX
}
_expiration_time`
)
return
Storage
.
get
(
`
${
PREFIX
}
_expiration_time`
)
;
}
getVersion
()
{
return
Storage
.
getObj
(
`
${
PREFIX
}
_version`
)
return
Storage
.
getObj
(
`
${
PREFIX
}
_version`
)
;
}
getStoreId
(){
return
window
.
currentStoreUserInfo
.
storeId
||
Storage
.
get
(
`
${
PREFIX
}
_storeId`
)
getStoreId
()
{
return
window
.
currentStoreUserInfo
.
storeId
||
Storage
.
get
(
`
${
PREFIX
}
_storeId`
);
}
getEnterpriseId
()
{
...
...
@@ -40,18 +39,22 @@ class User {
return
window
.
currentStoreUserInfo
.
storeUserId
||
Storage
.
get
(
`
${
PREFIX
}
_storeUserId`
);
}
getStoreUserName
()
{
return
Storage
.
get
(
`
${
PREFIX
}
_storeUserName`
);
}
getCustomerId
()
{
return
Storage
.
get
(
`
${
PREFIX
}
_customerId`
);
}
getUserId
()
{
return
window
.
currentStoreUserInfo
.
userId
||
Storage
.
get
(
`
${
PREFIX
}
_userId`
);
}
getAvatar
(){
getAvatar
()
{
return
Storage
.
get
(
`
${
PREFIX
}
_avatar`
);
}
getUserRole
()
{
return
Storage
.
get
(
`
${
PREFIX
}
_userRole`
);
}
...
...
@@ -64,16 +67,16 @@ class User {
return
Storage
.
get
(
`
${
PREFIX
}
_isAdmin`
);
}
setExpirationTime
(
value
:
number
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_expiration_time`
,
value
)
setExpirationTime
(
value
:
number
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_expiration_time`
,
value
);
}
setVersion
(
value
:
any
)
{
return
Storage
.
setObj
(
`
${
PREFIX
}
_version`
,
value
)
setVersion
(
value
:
any
)
{
return
Storage
.
setObj
(
`
${
PREFIX
}
_version`
,
value
);
}
setStoreId
(
value
:
any
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_storeId`
,
value
)
setStoreId
(
value
:
any
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_storeId`
,
value
);
}
setEnterpriseId
(
value
:
any
)
{
...
...
@@ -92,6 +95,10 @@ class User {
return
Storage
.
set
(
`
${
PREFIX
}
_storeUserId`
,
value
);
}
setStoreUserName
(
value
:
any
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_storeUserName`
,
value
);
}
setCustomerId
(
value
:
any
)
{
return
Storage
.
set
(
`
${
PREFIX
}
_customerId`
,
value
);
}
...
...
src/common/less/icon-font.less
View file @
b427be83
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_
7261tsts1dc.woff2?t=1628475376853
') format('woff2'),
url('//at.alicdn.com/t/font_2223403_
7261tsts1dc.woff?t=1628475376853
') format('woff'),
url('//at.alicdn.com/t/font_2223403_
7261tsts1dc.ttf?t=1628475376853
') format('truetype');
src: url('//at.alicdn.com/t/font_2223403_
0b87tvtysw45.woff2?t=1629025918841
') format('woff2'),
url('//at.alicdn.com/t/font_2223403_
0b87tvtysw45.woff?t=1629025918841
') format('woff'),
url('//at.alicdn.com/t/font_2223403_
0b87tvtysw45.ttf?t=1629025918841
') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
...
...
src/components/RichText.jsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useEffect
}
from
'react'
;
export
default
function
RichText
(
props
)
{
const
[
text
,
setText
]
=
useState
(
''
)
useEffect
(()
=>
{
console
.
log
(
props
.
url
,
'props.urlprops.url'
)
if
(
props
.
url
)
{
fetch
(
props
.
url
,
{
method
:
'GET'
}).
then
((
response
)
=>
{
return
response
.
text
();
}).
then
((
res
)
=>
{
setText
(
res
)
})
}
},
[
props
.
url
])
return
<
div
className=
"text"
style=
{
{
wordBreak
:
'break-all'
}
}
dangerouslySetInnerHTML=
{
{
__html
:
text
}
}
></
div
>
}
\ No newline at end of file
src/components/WWOpenData.jsx
View file @
b427be83
...
...
@@ -2,8 +2,6 @@ import React, { useRef, useLayoutEffect } from 'react'
export
default
function
WWOpenDataCom
({
type
,
openid
})
{
const
ref
=
useRef
(
null
)
useLayoutEffect
(()
=>
{
console
.
log
(
'1111'
);
console
.
log
(
WWOpenData
);
WWOpenData
&&
WWOpenData
.
bind
(
ref
.
current
)
})
return
<
ww
-
open
-
data
ref=
{
ref
}
type=
{
type
}
openid=
{
openid
}
/>
...
...
src/components/XMTable.jsx
View file @
b427be83
...
...
@@ -2,10 +2,14 @@ import React, { useEffect, useState } from 'react';
import
{
Empty
,
ConfigProvider
,
Table
}
from
'antd'
;
import
Lottie
from
'react-lottie'
;
import
*
as
nodata
from
'../modules/lottie/nodata/data.json'
;
import
college
from
'@/common/lottie/college'
;
function
XMTable
(
props
)
{
const
[
empty
,
setEmpty
]
=
useState
(
props
.
renderEmpty
||
{});
const
[
data
,
setData
]
=
useState
({});
const
imgType
=
{
college
}
useEffect
(()
=>
{
setEmpty
(
props
.
renderEmpty
||
{})
...
...
@@ -17,7 +21,7 @@ function XMTable(props) {
const
defaultOptions
=
{
loop
:
true
,
autoplay
:
true
,
animationData
:
empty
.
image
||
nodata
,
animationData
:
empty
.
image
||
imgType
[
props
?.
renderEmpty
?.
type
]
||
nodata
,
rendererSettings
:
{
preserveAspectRatio
:
'xMidYMid slice'
}
...
...
@@ -25,14 +29,14 @@ function XMTable(props) {
return
(
<
Empty
image=
{
<
div
style=
{
{
marginTop
:
24
}
}
>
<
Lottie
options=
{
defaultOptions
}
height=
{
150
}
width=
{
150
}
isStopped=
{
false
}
isPaused=
{
false
}
/>
</
div
>
}
<
Lottie
options=
{
defaultOptions
}
height=
{
150
}
width=
{
150
}
isStopped=
{
false
}
isPaused=
{
false
}
/>
</
div
>
}
imageStyle=
{
{
height
:
150
,
}
}
...
...
src/core/antd.less
View file @
b427be83
...
...
@@ -514,6 +514,7 @@ mr0 {
// 气泡
.ant-tooltip {
max-width: 280px !important;
.ant-tooltip-content {
.ant-tooltip-inner {
padding: 6px 12px !important;
...
...
src/core/global.less
View file @
b427be83
...
...
@@ -1706,22 +1706,40 @@ input:focus {
background: transparent !important;
}
.xm_search_item {
padding-right: 24px;
width: 100%;
display: flex;
align-items: center;
flex-wrap: wrap;
box-sizing: border-box;
.label{
margin-right: 8px;
flex-shrink: 0;
// height: 36px;
// line-height: 36px;
}
.search{
flex: 1;
}
.createQWCourse{
.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;
.createQWCourse{
.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/core/page.less
View file @
b427be83
...
...
@@ -22,7 +22,7 @@
z-index: 102;
overflow: auto;
margin: 0 16px;
min-height: auto;
.box {
&:first-child {
margin-bottom: 8px;
...
...
src/data-source/taskCenter/request-apis.ts
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-06 17:35:35
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 20:52:16
* @Description: 任务中心接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
Service
from
'@/common/js/service'
;
export
function
getTrainingTaskPage
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getTrainingTaskPage'
,
params
);
}
export
function
getStoreTaskNum
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getStoreTaskNum'
,
params
);
}
export
function
createTrainingExam
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/createTrainingExam'
,
params
);
}
export
function
createTrainingTask
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/createTrainingTask'
,
params
);
}
export
function
updateIssueStateTraining
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/updateIssueStateTraining'
,
params
);
}
export
function
deleteTrainingTask
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/deleteTrainingTask'
,
params
);
}
export
function
getTrainingTaskDetail
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getTrainingTaskDetail'
,
params
);
}
export
function
updateTrainingTask
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/updateTrainingTask'
,
params
);
}
export
function
getTaskCustomerDetail
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getTaskCustomerDetail'
,
params
);
}
export
function
updateTrainingTaskAssign
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/updateTrainingTaskAssign'
,
params
);
}
export
function
getTrainingCourseAutoCancel
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getTrainingCourseAutoCancel'
,
params
);
}
export
function
delTaskCancelContent
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/delTaskCancelContent'
,
params
);
}
export
function
getStoreTaskAll
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/getStoreTaskAll'
,
params
);
}
export
function
relatedCourseToTask
(
params
:
object
)
{
return
Service
.
Hades
(
'public/hades/relatedCourseToTask'
,
params
);
}
src/domains/basic-domain/constants.ts
View file @
b427be83
/*
* @Author: 陈剑宇
* @Date: 2020-05-07 14:43:01
* @LastEditTime: 2021-0
8-11 22:52:0
4
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
9-03 10:28:1
4
* @LastEditors:
wufan
* @Description:
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
*/
...
...
src/domains/course-domain/constants.ts
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-08-20 09:21:40
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
8-11 22:50:48
* @LastEditors:
wufan
* @LastEditTime: 2021-0
9-03 10:28:17
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
...
...
src/domains/task-center-domain/TaskCenterService.ts
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-06 17:32:41
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 20:56:36
* @Description: 任务中心-培训任务接口
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
{
getTrainingTaskPage
,
getStoreTaskNum
,
createTrainingExam
,
createTrainingTask
,
updateIssueStateTraining
,
deleteTrainingTask
,
getTrainingTaskDetail
,
updateTrainingTask
,
getTaskCustomerDetail
,
updateTrainingTaskAssign
,
getTrainingCourseAutoCancel
,
delTaskCancelContent
,
getStoreTaskAll
,
relatedCourseToTask
,
}
from
'@/data-source/taskCenter/request-apis'
;
export
default
class
TaskCenterService
{
// 获取培训任务列表
static
getTrainingTaskPage
(
params
:
any
)
{
return
getTrainingTaskPage
(
params
);
}
// 获取学院任务数量
static
getStoreTaskNum
(
params
:
any
)
{
return
getStoreTaskNum
(
params
);
}
// 培训任务创建考试
static
createTrainingExam
(
params
:
any
)
{
return
createTrainingExam
(
params
);
}
// 企培创建培训任务
static
createTrainingTask
(
params
:
any
)
{
return
createTrainingTask
(
params
);
}
// 发布/取消发布培训任务
static
updateIssueStateTraining
(
params
:
any
)
{
return
updateIssueStateTraining
(
params
);
}
// 删除培训任务
static
deleteTrainingTask
(
params
:
any
)
{
return
deleteTrainingTask
(
params
);
}
// 获取培训任务详情
static
getTrainingTaskDetail
(
params
:
any
)
{
return
getTrainingTaskDetail
(
params
);
}
// 修改培训任务
static
updateTrainingTask
(
params
:
any
)
{
return
updateTrainingTask
(
params
);
}
// 获取单个任务单个学员的学习进度详情
static
getTaskCustomerDetail
(
params
:
any
)
{
return
getTaskCustomerDetail
(
params
);
}
// 修改培训任务的指派信息
static
updateTrainingTaskAssign
(
params
:
any
)
{
return
updateTrainingTaskAssign
(
params
);
}
// 获取培训任务失效的课程
static
getTrainingCourseAutoCancel
(
params
:
any
)
{
return
getTrainingCourseAutoCancel
(
params
);
}
// 删除失效课程
static
delTaskCancelContent
(
params
:
any
)
{
return
delTaskCancelContent
(
params
);
}
// 获取培训任务学习基本信息
static
getStoreTaskAll
(
params
:
any
)
{
return
getStoreTaskAll
(
params
);
}
// 课程关联培训任务
static
relatedCourseToTask
(
params
:
any
)
{
return
relatedCourseToTask
(
params
);
}
}
src/h5.html
View file @
b427be83
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
5-26 16:26:17
* @LastEditors:
wufan
* @LastEditTime: 2021-0
8-15 19:12:48
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
...
...
@@ -25,7 +25,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link
rel=
"manifest"
href=
"%PUBLIC_URL%/manifest.json"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
oqqm4z9s35j
.css"
>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
0b87tvtysw45
.css"
>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
...
...
src/index.d.ts
View file @
b427be83
/*
* @Author: wufan
* @Date: 2021-09-03 10:23:20
* @LastEditors: wufan
* @LastEditTime: 2021-09-03 10:24:30
* @Description: Description
* @@Copyrigh: © 2021 杭州杰竞科技有限公司 版权所有
*/
declare
module
'jquery'
declare
module
'cropper'
declare
module
'ExamShareModal'
declare
module
'college'
declare
module
'@/common/lottie/college'
declare
module
'routeHooks'
// declare var this: any
\ No newline at end of file
src/index.html
View file @
b427be83
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
8-11 20:25:11
* @LastEditors:
wufan
* @LastEditTime: 2021-0
9-03 10:26:25
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
...
...
@@ -25,14 +25,14 @@
<!-- <link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png" /> -->
<!-- <link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/WGWCtxiGzE.png"> -->
<!--
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link
rel=
"manifest"
href=
"%PUBLIC_URL%/manifest.json"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_7261tsts1dc.css"
/>
<!--
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
...
...
@@ -62,7 +62,7 @@
</script>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div
id=
"root"
></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
...
...
@@ -73,5 +73,5 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</body>
</html>
src/modules/college-manage/EmployeeManage.tsx
View file @
b427be83
...
...
@@ -5,21 +5,21 @@
* @Last Modified time: 2021-04-10 14:36:43
* 学院管理-员工管理
*/
import
React
,
{
useEffect
,
useState
}
from
"react"
;
import
{
withRouter
}
from
"react-router-dom"
;
import
_
from
"underscore"
;
import
{
CheckBox
,
PageControl
}
from
"@/components"
;
import
{
Button
,
Table
,
Modal
,
message
,
Input
,
Tooltip
}
from
"antd"
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
'react-router-dom'
;
import
_
from
'underscore'
;
import
{
CheckBox
,
PageControl
}
from
'@/components'
;
import
{
Button
,
Table
,
Modal
,
message
,
Input
,
Tooltip
}
from
'antd'
;
import
{
XMTable
}
from
'@/components'
;
import
college
from
'@/common/lottie/college.json'
;
import
StoreService
from
"@/domains/store-domain/storeService"
;
import
EmployeeAddOrEditModal
from
"../store-manage/EmployeeAddOrEditModal"
;
import
User
from
"@/common/js/user"
;
import
LimitTip
from
"./LimitTip"
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
EmployeeAddOrEditModal
from
'../store-manage/EmployeeAddOrEditModal'
;
import
User
from
'@/common/js/user'
;
import
LimitTip
from
'./LimitTip'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
import
"./EmployeeManage.less"
;
import
NewChooseMembersModal
from
"./modal/NewChooseMembersModal"
;
import
'./EmployeeManage.less'
;
import
NewChooseMembersModal
from
'./modal/NewChooseMembersModal'
;
const
{
confirm
}
=
Modal
;
const
{
Search
}
=
Input
;
...
...
@@ -33,7 +33,7 @@ interface RecordTypes {
phone
:
string
;
avatar
?:
string
;
weChatAccount
?:
string
;
depNameList
:
any
depNameList
:
any
;
}
interface
RoleItemType
{
...
...
@@ -58,7 +58,7 @@ interface ChoosedItemType {
avatar
?:
string
;
storeUserId
?:
string
;
weChatAccount
?:
string
;
depNameList
?:
any
;
depNameList
?:
any
;
}
function
EmployeeManage
()
{
...
...
@@ -66,25 +66,25 @@ function EmployeeManage() {
const
[
query
,
setQuery
]
=
useState
<
QueryType
>
({
current
:
0
,
size
:
10
,
nickName
:
""
,
phone
:
""
,
nickName
:
''
,
phone
:
''
,
roleCodes
:
[],
});
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
realTotal
,
setRealTotal
]
=
useState
(
0
)
const
[
realTotal
,
setRealTotal
]
=
useState
(
0
)
;
const
[
model
,
setModel
]
=
useState
<
React
.
ReactNode
>
(
null
);
const
[
employeeModal
,
setEmployeeModal
]
=
useState
(
false
);
const
[
choosedItem
,
setChooseItem
]
=
useState
<
ChoosedItemType
>
({
nickName
:
""
,
phone
:
""
,
nickName
:
''
,
phone
:
''
,
role
:
[],
avatar
:
""
,
avatar
:
''
,
});
const
[
roleIds
,
setRoleIds
]
=
useState
<
Array
<
RoleItemType
>>
([]);
const
storeId
=
User
.
getStoreId
();
const
StoreType
=
User
.
getStoreType
();
const
isWorkWechat
=
!!
(
StoreType
===
"WE_CHAT_STORE"
);
const
isWorkWechat
=
!!
(
StoreType
===
'WE_CHAT_STORE'
);
useEffect
(()
=>
{
if
(
!
User
.
getEnterpriseId
())
{
...
...
@@ -94,14 +94,14 @@ function EmployeeManage() {
const
_query
=
{
current
:
0
,
size
:
10
,
nickName
:
""
,
phone
:
""
,
nickName
:
''
,
phone
:
''
,
roleCodes
:
[],
}
}
;
StoreService
.
getEmployeeList
(
_query
).
then
((
res
:
any
)
=>
{
setRealTotal
(
res
.
result
.
total
);
});
},
[])
},
[])
;
useEffect
(()
=>
{
getEmployeeList
();
...
...
@@ -130,7 +130,7 @@ function EmployeeManage() {
const
_query
=
{
...
query
};
let
_data
=
_
.
filter
(
data
,
(
_item
)
=>
{
return
_item
.
roleCode
!==
"StoreManager"
;
return
_item
.
roleCode
!==
'StoreManager'
;
});
setRoleIds
(
_data
);
...
...
@@ -145,29 +145,21 @@ function EmployeeManage() {
fixed
:
'left'
,
render
:
(
val
:
string
,
record
:
RecordTypes
)
=>
{
return
(
<
div
className=
"employee-info"
>
{
isWorkWechat
&&
(
<
img
src=
{
record
.
avatar
||
"https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png"
}
alt=
""
/>
)
}
<
div
className=
'employee-info'
>
{
isWorkWechat
&&
<
img
src=
{
record
.
avatar
||
'https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png'
}
alt=
''
/>
}
{
/* <span className="title">{val}</span> */
}
<
span
className=
"title"
>
<
WWOpenDataCom
type=
"userName"
openid=
{
val
}
/>
<
span
className=
'title'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
val
}
/>
</
span
>
</
div
>
);
},
},
{
title
:
"手机号"
,
dataIndex
:
"phone"
,
key
:
"phone"
,
title
:
'手机号'
,
dataIndex
:
'phone'
,
key
:
'phone'
,
render
:
(
val
:
string
)
=>
{
return
<
div
>
{
val
||
'-'
}
</
div
>;
},
...
...
@@ -180,8 +172,8 @@ function EmployeeManage() {
if
(
!
record
.
depNameList
){
return
<
span
>
-
</
span
>
}
if
(
record
.
depNameList
.
length
===
0
)
{
return
<
span
>
-
</
span
>
if
(
record
.
depNameList
.
length
===
0
)
{
return
<
span
>
-
</
span
>
;
}
return
<
Tooltip
title=
{
<
div
>
{
handleDepName
(
record
.
depNameList
)
}
</
div
>
}
placement=
'top'
arrowPointAtCenter
><
div
className=
"post-name"
>
{
record
.
depNameList
.
map
((
item
:
any
,
index
:
any
)
=>
{
return
<
span
><
WWOpenDataCom
type=
"departmentName"
openid=
{
item
}
/>
{
index
<
(
record
.
depNameList
.
length
-
1
)?
';'
:
''
}
</
span
>
...
...
@@ -195,7 +187,7 @@ function EmployeeManage() {
dataIndex
:
"role"
,
key
:
"role"
,
render
:
(
val
:
string
)
=>
{
return
<
div
>
{
val
.
split
(
","
).
join
(
"、"
)
}
</
div
>;
return
<
div
>
{
val
.
split
(
','
).
join
(
'、'
)
}
</
div
>;
},
},
{
...
...
@@ -203,34 +195,19 @@ function EmployeeManage() {
dataIndex
:
"operation"
,
fixed
:
'right'
,
render
:
(
val
:
string
,
record
:
RecordTypes
)
=>
{
return
record
.
role
===
"学院管理员"
||
record
.
userId
===
User
.
getUserId
()
?
(
<
div
className=
"no-operate"
>
-
</
div
>
return
record
.
role
===
'学院管理员'
||
record
.
userId
===
User
.
getUserId
()
?
(
<
div
className=
'no-operate'
>
-
</
div
>
)
:
(
<
div
className=
"operation"
>
{
!
record
.
depNameList
&&
<
span
className=
"edit edit-disable"
>
编辑
</
span
>
}
{
record
.
depNameList
&&
(
record
.
depNameList
.
length
>
0
?
<
span
className=
"edit"
onClick=
{
()
=>
handleEditEmployee
(
record
)
}
>
编辑
</
span
>
:
<
span
className=
"edit edit-disable"
>
编辑
</
span
>
)
}
<
span
className=
"divider-line"
>
{
" | "
}
</
span
>
<
div
className=
'operation'
>
<
span
className=
'edit'
onClick=
{
()
=>
handleEditEmployee
(
record
)
}
>
编辑
</
span
>
<
span
className=
'divider-line'
>
{
' | '
}
</
span
>
<
span
className=
"delete"
onClick=
{
()
=>
{
handleDeleteWorkWechatEmployeeConfirm
(
record
)
}
}
>
className=
'delete'
onClick=
{
()
=>
{
handleDeleteWorkWechatEmployeeConfirm
(
record
);
}
}
>
删除
</
span
>
</
div
>
...
...
@@ -241,9 +218,9 @@ function EmployeeManage() {
if
(
isWorkWechat
&&
columns
)
{
const
item
=
{
title
:
"企业微信账号"
,
dataIndex
:
"weChatAccount"
,
key
:
"weChatAccount"
,
title
:
'企业微信账号'
,
dataIndex
:
'weChatAccount'
,
key
:
'weChatAccount'
,
render
:
(
val
:
string
)
=>
{
return
<
div
>
{
val
}
</
div
>;
},
...
...
@@ -253,15 +230,19 @@ function EmployeeManage() {
return
columns
;
}
function
handleDepName
(
depArray
:
any
):
any
{
const
depArrayDom
=
depArray
.
map
((
item
:
any
,
index
:
any
)
=>
{
return
<
span
><
WWOpenDataCom
type=
"departmentName"
openid=
{
item
}
/>
;
</
span
>
function
handleDepName
(
depArray
:
any
):
any
{
const
depArrayDom
=
depArray
.
map
((
item
:
any
,
index
:
any
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
;
</
span
>
);
});
return
depArrayDom
;
}
;
}
function
handleEditEmployee
(
record
:
RecordTypes
)
{
const
{
nickName
,
phone
,
roleCodes
,
avatar
,
id
,
weChatAccount
,
depNameList
}
=
record
;
const
{
nickName
,
phone
,
roleCodes
,
avatar
,
id
,
weChatAccount
,
depNameList
}
=
record
;
const
_choosesItem
=
{
nickName
:
nickName
,
phone
:
phone
,
...
...
@@ -269,7 +250,7 @@ function EmployeeManage() {
avatar
:
avatar
,
storeUserId
:
id
,
weChatAccount
,
depNameList
:
depNameList
depNameList
:
depNameList
,
};
setChooseItem
(
_choosesItem
);
const
model
:
React
.
ReactNode
=
(
...
...
@@ -279,13 +260,13 @@ function EmployeeManage() {
setModel
(
null
);
getEmployeeList
();
setChooseItem
({
nickName
:
""
,
phone
:
""
,
nickName
:
''
,
phone
:
''
,
role
:
[],
avatar
:
""
,
storeUserId
:
""
,
weChatAccount
:
""
,
depNameList
:
[]
avatar
:
''
,
storeUserId
:
''
,
weChatAccount
:
''
,
depNameList
:
[],
});
}
}
isWorkWechat=
{
isWorkWechat
}
...
...
@@ -296,14 +277,12 @@ function EmployeeManage() {
function
handleDeleteWorkWechatEmployeeConfirm
(
record
:
RecordTypes
)
{
return
confirm
({
title
:
"你确定要删除此员工吗?"
,
content
:
"删除后数据无法恢复"
,
icon
:
(
<
span
className=
"icon iconfont default-confirm-icon"
>

</
span
>
),
okText
:
"删除"
,
okType
:
"danger"
,
cancelText
:
"取消"
,
title
:
'你确定要删除此员工吗?'
,
content
:
'删除后数据无法恢复'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
okText
:
'删除'
,
okType
:
'danger'
,
cancelText
:
'取消'
,
onOk
:
()
=>
{
handleDeleteEmployee
(
record
.
id
);
},
...
...
@@ -316,21 +295,21 @@ function EmployeeManage() {
function
handleDeleteEmployee
(
storeUserId
:
string
)
{
StoreService
.
deleteEmployee
({
storeUserId
}).
then
((
res
:
any
)
=>
{
const
msg
=
isWorkWechat
?
"员工已删除"
:
"讲师已删除"
;
const
msg
=
isWorkWechat
?
'员工已删除'
:
'讲师已删除'
;
message
.
success
(
msg
);
getEmployeeList
();
});
}
function
updateListData
(){
let
num
:
any
;
function
updateListData
()
{
let
num
:
any
;
const
params
=
{
enterpriseId
:
User
.
getEnterpriseId
(),
storeId
:
User
.
getStoreId
(),
userType
:
'USER'
}
enterpriseId
:
User
.
getEnterpriseId
(),
storeId
:
User
.
getStoreId
(),
userType
:
'USER'
,
}
;
StoreService
.
getSyncCount
(
params
).
then
((
res
)
=>
{
num
=
res
.
result
;
if
(
num
<
3
)
{
if
(
num
<
3
)
{
return
confirm
({
title
:
"确定更新列表数据吗?"
,
content
:
<
span
>
员工数据来源企微通讯录,一天只能更新3次,今日还能更新
<
span
style=
{
{
color
:
'#2966FF'
}
}
>
{
3
-
num
}
</
span
>
次。
</
span
>,
...
...
@@ -340,10 +319,10 @@ function EmployeeManage() {
okText
:
"确定"
,
cancelText
:
"取消"
,
onOk
:
()
=>
{
confirmUpdateListData
()
confirmUpdateListData
()
;
},
});
}
else
{
}
else
{
Modal
.
warning
({
title
:
'提示'
,
okText
:
'我知道了'
,
...
...
@@ -356,109 +335,101 @@ function EmployeeManage() {
});
}
});
}
function
confirmUpdateListData
(){
function
confirmUpdateListData
()
{
const
params
=
{
enterpriseId
:
User
.
getEnterpriseId
(),
storeId
:
User
.
getStoreId
(),
userType
:
'USER'
}
enterpriseId
:
User
.
getEnterpriseId
(),
storeId
:
User
.
getStoreId
(),
userType
:
'USER'
,
}
;
StoreService
.
syncWorkWeChatDepartment
(
params
).
then
((
res
)
=>
{
getEmployeeList
();
message
.
success
(
'已更新'
);
});
}
return
(
<
div
className=
"page employee-manage-page"
>
<
div
className=
"content-header"
>
角色管理
</
div
>
<
div
className=
"box"
>
<
div
className=
"box-header"
>
<
div
style=
{
{
display
:
"flex"
,
alignItems
:
"center"
,
justifyContent
:
"flex-start"
,
padding
:
"0px 0 4px"
,
}
}
>
<
div
>
<
div
className=
'page employee-manage-page'
>
<
div
className=
'content-header'
>
角色管理
</
div
>
<
div
className=
'box'
>
<
div
className=
'box-header'
>
<
div
style=
{
{
display
:
'flex'
,
alignItems
:
'center'
,
justifyContent
:
'flex-start'
,
padding
:
'0px 0 4px'
,
}
}
>
<
div
>
搜索员工:
<
Search
style=
{
{
width
:
300
,
marginRight
:
40
,
}
}
placeholder=
{
isWorkWechat
?
"请输入员工昵称"
:
"搜索员工昵称/手机号"
<
Search
style=
{
{
width
:
300
,
marginRight
:
40
,
}
}
placeholder=
{
isWorkWechat
?
'请输入员工昵称'
:
'搜索员工昵称/手机号'
}
onSearch=
{
(
value
)
=>
{
const
_query
=
{
...
query
};
// 企业微信用户只能搜索员工昵称
if
(
isWorkWechat
)
{
_query
.
nickName
=
value
;
_query
.
current
=
0
;
setQuery
(
_query
);
return
;
}
onSearch=
{
(
value
)
=>
{
const
_query
=
{
...
query
};
// 企业微信用户只能搜索员工昵称
if
(
isWorkWechat
)
{
_query
.
nickName
=
value
;
_query
.
current
=
0
;
setQuery
(
_query
);
return
;
}
if
(
value
)
{
const
isPhone
=
(
value
||
""
).
match
(
/^
\d
+$/
);
const
name
=
isPhone
?
"phone"
:
"nickName"
;
const
otherName
=
isPhone
?
"nickName"
:
"phone"
;
_query
[
name
]
=
value
;
_query
[
otherName
]
=
""
;
_query
.
current
=
0
;
}
else
{
_query
.
nickName
=
""
;
_query
.
phone
=
""
;
_query
.
current
=
0
;
}
setQuery
(
_query
);
}
}
enterButton=
{
<
span
className=
"icon iconfont"
>

</
span
>
}
/>
</
div
>
if
(
value
)
{
const
isPhone
=
(
value
||
''
).
match
(
/^
\d
+$/
);
const
name
=
isPhone
?
'phone'
:
'nickName'
;
const
otherName
=
isPhone
?
'nickName'
:
'phone'
;
_query
[
name
]
=
value
;
_query
[
otherName
]
=
''
;
_query
.
current
=
0
;
}
else
{
_query
.
nickName
=
''
;
_query
.
phone
=
''
;
_query
.
current
=
0
;
}
setQuery
(
_query
);
}
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
/>
</
div
>
<
div
>
角色:
{
_
.
map
(
roleIds
,
(
item
:
any
)
=>
{
return
(
<
CheckBox
key=
{
item
.
roleCode
}
text=
{
item
.
name
}
name=
{
item
.
roleCode
}
onChange=
{
(
e
:
any
)
=>
{
const
{
checked
,
name
}
=
e
.
target
;
const
_query
=
{
...
query
};
_query
.
roleCodes
=
[];
_query
.
current
=
0
;
const
_roleIds
:
Array
<
RoleItemType
>
=
roleIds
.
map
(
(
_item
:
RoleItemType
)
=>
{
if
(
name
===
_item
.
roleCode
)
{
if
(
checked
)
{
_item
.
isChecked
=
true
;
}
else
{
_item
.
isChecked
=
false
;
}
}
if
(
_item
.
isChecked
)
{
_query
.
roleCodes
.
push
(
_item
.
roleCode
);
}
return
_item
;
<
div
>
角色:
{
_
.
map
(
roleIds
,
(
item
:
any
)
=>
{
return
(
<
CheckBox
key=
{
item
.
roleCode
}
text=
{
item
.
name
}
name=
{
item
.
roleCode
}
onChange=
{
(
e
:
any
)
=>
{
const
{
checked
,
name
}
=
e
.
target
;
const
_query
=
{
...
query
};
_query
.
roleCodes
=
[];
_query
.
current
=
0
;
const
_roleIds
:
Array
<
RoleItemType
>
=
roleIds
.
map
((
_item
:
RoleItemType
)
=>
{
if
(
name
===
_item
.
roleCode
)
{
if
(
checked
)
{
_item
.
isChecked
=
true
;
}
else
{
_item
.
isChecked
=
false
;
}
);
}
if
(
_item
.
isChecked
)
{
_query
.
roleCodes
.
push
(
_item
.
roleCode
);
}
return
_item
;
});
setRoleIds
(
_roleIds
);
setQuery
(
_query
);
}
}
defaultChecked=
{
item
.
isChecked
}
/>
);
})
}
</
div
>
setRoleIds
(
_roleIds
);
setQuery
(
_query
);
}
}
defaultChecked=
{
item
.
isChecked
}
/>
);
})
}
</
div
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
<>
...
...
@@ -510,21 +481,84 @@ function EmployeeManage() {
}
}
/>
</
div
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<>
<
Button
onClick=
{
()
=>
{
handleToAddEmployee
();
}
}
type=
'primary'
className=
'add-show-btn'
>
添加员工
</
Button
>
<
Button
className=
'update-user-btn'
onClick=
{
()
=>
{
updateListData
();
}
}
>
更新列表数据
</
Button
>
<
span
className=
'origin-text'
>
数据来源企业微信通讯录
</
span
>
<
a
href=
'https://www.yuque.com/wangzhong-zkqw0/qixue'
target=
'_blank'
>
<
span
className=
'view-text'
>
查看数据更新说明
</
span
>
</
a
>
</>
)
}
</
div
>
<
LimitTip
type=
'员工'
total=
{
realTotal
}
tip=
{
()
=>
{
return
<
div
>
数据为当前学院的员工数,若员工存在多个学院,企业人数只统计为1人
</
div
>;
}
}
/>
<
div
className=
'box-body'
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
size=
{
'middle'
}
pagination=
{
false
}
dataSource=
{
employeeList
}
columns=
{
parseColumn
()
}
rowKey=
{
(
item
:
any
)
=>
item
.
id
}
bordered
/>
</
div
>
{
model
}
{
employeeModal
&&
{
employeeModal
&&
(
<
NewChooseMembersModal
treeDepType=
"DEP_CHAT"
treeDepType=
'DEP_CHAT'
visible=
{
employeeModal
}
type=
"USER"
close=
{
()
=>
{
setEmployeeModal
(
false
)}
}
type=
'USER'
close=
{
()
=>
{
setEmployeeModal
(
false
);
}
}
onConfirm=
{
()
=>
{
setEmployeeModal
(
false
)
message
.
success
(
'添加成功'
)
setEmployeeModal
(
false
)
;
message
.
success
(
'添加成功'
)
;
getEmployeeList
();
}
}
}
}
/>
)
}
{
model
}
{
employeeModal
&&
(
<
NewChooseMembersModal
treeDepType=
'DEP_CHAT'
visible=
{
employeeModal
}
type=
'USER'
close=
{
()
=>
{
setEmployeeModal
(
false
);
}
}
onConfirm=
{
()
=>
{
setEmployeeModal
(
false
);
message
.
success
(
'添加成功'
);
getEmployeeList
();
}
}
/>
}
)
}
</
div
>
</
div
>
);
}
...
...
src/modules/college-manage/modal/SetEmployeeModal.jsx
View file @
b427be83
...
...
@@ -5,7 +5,6 @@ import './SetEmployeeModal.less'
const
RadioGroup
=
Radio
.
Group
;
const
tagMap
=
{
Cloud_Operator
:
'运营师'
,
Cloud_Lecturer
:
'讲师'
,
Cloud_Manager
:
'管理员'
,
}
...
...
@@ -105,12 +104,6 @@ export default class SetEmployeeModal extends React.Component {
}
}
className=
"mt5"
>
<
Radio
value=
{
"Cloud_Operator"
}
className=
"mt-4"
>
<
span
style=
{
{
color
:
"#333"
}
}
>
运营师
</
span
>
<
p
className=
"radio-tip"
>
仅可查看/转发培训计划内容,并查看负责的学员学习进度
</
p
>
</
Radio
>
<
Radio
value=
{
"Cloud_Lecturer"
}
className=
"mt-4"
>
<
span
style=
{
{
color
:
"#333"
}
}
>
讲师
</
span
>
<
p
className=
"radio-tip"
>
...
...
src/modules/course-manage/components/GraphicsEditor.jsx
View file @
b427be83
...
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-05 10:47:19
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-12 17:13:38
* @LastEditTime: 2021-0
8-02 17:54:13
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
...
...
@@ -49,7 +49,7 @@ class GraphicsEditor extends React.Component {
renderEditor
()
{
const
{
editorId
}
=
this
.
state
;
const
{
detail
,
onChange
,
isIntro
,
maxLimit
,
editorType
}
=
this
.
props
;
const
{
detail
,
onChange
,
isIntro
,
maxLimit
,
editorType
,
placeholder
=
'请输入正文'
}
=
this
.
props
;
class
ImageMenu
extends
BtnMenu
{
constructor
(
editor
)
{
// data-title属性表示当鼠标悬停在该按钮上时提示该按钮的功能简述
...
...
@@ -89,6 +89,7 @@ class GraphicsEditor extends React.Component {
this
.
editorInt
=
new
E
(
`#editor
${
editorId
}
`
);
this
.
editorInt
.
config
.
focus
=
false
;
this
.
editorInt
.
config
.
showFullScreen
=
!
isIntro
;
this
.
editorInt
.
config
.
placeholder
=
placeholder
;
this
.
editorInt
.
menus
.
extend
(
'xmimage'
,
ImageMenu
);
!
isIntro
&&
this
.
editorInt
.
menus
.
extend
(
'xmvideo'
,
VideoMenu
);
this
.
editorInt
.
config
.
menus
=
isIntro
...
...
src/modules/course-manage/components/LiveCourseList.jsx
View file @
b427be83
...
...
@@ -28,7 +28,7 @@ import Bus from '@/core/bus';
import
'./LiveCourseList.less'
;
import
{
brandLiveName
}
from
'@/domains/brand/constants'
;
const
{
confirm
}
=
Modal
const
{
confirm
}
=
Modal
;
const
courseStateShow
=
{
UN_START
:
{
code
:
1
,
...
...
@@ -50,20 +50,20 @@ const courseStateShow = {
title
:
'未成功开课'
,
color
:
'#999'
,
},
}
}
;
class
LiveCourseList
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
)
super
(
props
)
;
this
.
state
=
{
columns
:
[],
openDownloadModal
:
false
,
url
:
''
,
RelatedPlanModalVisible
:
false
,
selectPlanList
:
{},
}
}
;
}
componentWillMount
()
{
this
.
parseColumns
()
this
.
parseColumns
()
;
}
componentDidMount
()
{
this
.
getDownloadVersion
()
...
...
@@ -73,13 +73,12 @@ class LiveCourseList extends React.Component {
}
// 显示分享弹窗
handleShowShareModal
=
(
item
,
needStr
=
false
)
=>
{
const
{
liveCourseId
}
=
item
const
{
liveCourseId
}
=
item
;
const
htmlUrl
=
`
${
LIVE_SHARE
}
live_detail/
${
liveCourseId
}
?id=
${
User
.
getStoreId
()}
`
const
longUrl
=
htmlUrl
console
.
log
(
'htmlUrl'
,
htmlUrl
,
longUrl
)
const
htmlUrl
=
`
${
LIVE_SHARE
}
live_detail/
${
liveCourseId
}
?id=
${
User
.
getStoreId
()}
`
;
const
longUrl
=
htmlUrl
;
const
shareData
=
{
...
item
,
longUrl
}
const
shareData
=
{
...
item
,
longUrl
}
;
const
shareLiveModal
=
(
<
ShareLiveModal
needStr=
{
needStr
}
...
...
@@ -89,33 +88,33 @@ class LiveCourseList extends React.Component {
close=
{
()
=>
{
this
.
setState
({
shareLiveModal
:
null
,
})
localStorage
.
setItem
(
'largeLiveCourseItem'
,
''
)
})
;
localStorage
.
setItem
(
'largeLiveCourseItem'
,
''
)
;
}
}
/>
)
)
;
this
.
setState
({
shareLiveModal
})
}
this
.
setState
({
shareLiveModal
})
;
}
;
//改变上架状态
changeShelfState
=
(
index
,
item
,
checked
)
=>
{
let
_shelfState
=
checked
?
'YES'
:
'NO'
let
_shelfState
=
checked
?
'YES'
:
'NO'
;
const
params
=
{
liveCourseId
:
item
.
liveCourseId
,
shelfState
:
_shelfState
,
}
}
;
CourseService
.
turnOnOrOffLiveCloudCourse
(
params
).
then
((
res
)
=>
{
if
(
res
.
success
)
{
if
(
_shelfState
===
'YES'
)
{
message
.
success
(
'已开启展示'
)
message
.
success
(
'已开启展示'
)
;
}
else
{
message
.
success
(
'已取消展示'
)
message
.
success
(
'已取消展示'
)
;
}
this
.
props
.
changeShelfState
(
index
,
_shelfState
)
this
.
props
.
changeShelfState
(
index
,
_shelfState
)
;
}
})
}
})
;
}
;
// 前往上课数据页面
handleLinkToClassData
=
(
item
)
=>
{
...
...
@@ -126,8 +125,8 @@ class LiveCourseList extends React.Component {
});
};
parseColumns
=
()
=>
{
let
columns
const
userRole
=
User
.
getUserRole
()
let
columns
;
const
userRole
=
User
.
getUserRole
()
;
if
(
userRole
!==
'CloudLecturer'
)
{
columns
=
[
{
...
...
@@ -137,15 +136,15 @@ class LiveCourseList extends React.Component {
fixed
:
'left'
,
dataIndex
:
'courseName'
,
render
:
(
val
,
record
)
=>
{
let
hasCover
=
false
let
hasCover
=
false
;
return
(
<
div
className=
'record__item'
>
{
record
.
courseMediaVOS
.
map
((
item
,
index
)
=>
{
if
(
item
.
contentType
===
'COVER'
)
{
hasCover
=
true
return
<
img
key=
{
item
.
mediaContent
+
index
}
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>
hasCover
=
true
;
return
<
img
key=
{
item
.
mediaContent
+
index
}
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>
;
}
else
{
return
null
return
null
;
}
})
}
{
!
hasCover
&&
<
img
className=
'course-cover'
src=
{
'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'
}
alt=
''
/>
}
...
...
@@ -191,7 +190,7 @@ class LiveCourseList extends React.Component {
<
span
key=
{
item
.
adminId
+
index
}
>
{
item
.
adminName
}
{
index
<
record
.
admins
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
span
>
</
Tooltip
>
...
...
@@ -204,7 +203,7 @@ class LiveCourseList extends React.Component {
<
span
>
{
item
.
adminName
}
{
index
<
record
.
admins
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
span
>
</
Otherwise
>
...
...
@@ -213,7 +212,7 @@ class LiveCourseList extends React.Component {
</
div
>
</
div
>
</
div
>
)
)
;
},
},
{
...
...
@@ -244,7 +243,7 @@ class LiveCourseList extends React.Component {
key
:
'couseCatalog'
,
dataIndex
:
'couseCatalog'
,
render
:
(
val
,
item
)
=>
{
return
<
div
className=
'categoryName'
>
{
item
.
categorySonName
}
</
div
>
return
<
div
className=
'categoryName'
>
{
item
.
categorySonName
}
</
div
>
;
},
},
{
...
...
@@ -260,11 +259,11 @@ class LiveCourseList extends React.Component {
this
.
setState
({
editData
:
item
,
openCoursewareModal
:
true
,
})
})
;
}
}
>
{
item
.
courseDocumentCount
}
个
</
span
>
)
)
;
},
},
{
...
...
@@ -277,11 +276,11 @@ class LiveCourseList extends React.Component {
<
span
className=
'iconfont icon quota-icon'
onClick=
{
()
=>
{
this
.
handleLinkToClassData
(
item
)
this
.
handleLinkToClassData
(
item
)
;
}
}
>

</
span
>
)
)
;
},
},
{
...
...
@@ -313,7 +312,7 @@ class LiveCourseList extends React.Component {
defaultChecked=
{
item
.
shelfState
===
'YES'
?
true
:
false
}
onChange=
{
(
checked
)
=>
this
.
changeShelfState
(
index
,
item
,
checked
)
}
/>
)
)
;
},
},
{
...
...
@@ -324,7 +323,7 @@ class LiveCourseList extends React.Component {
sorter
:
true
,
render
:
(
val
,
item
)
=>
{
// -29000:与后端约定 在初始化学院时,创建时间(标志位-29000)默认展示为'-'
return
<
span
style=
{
{
whiteSpace
:
'nowrap'
}
}
>
{
val
===
-
29000
?
'-'
:
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>
return
<
span
style=
{
{
whiteSpace
:
'nowrap'
}
}
>
{
val
===
-
29000
?
'-'
:
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>
;
},
},
{
...
...
@@ -343,7 +342,7 @@ class LiveCourseList extends React.Component {
<
span
key=
{
index
}
>
{
item
.
planName
}
{
index
<
record
.
relatedPlanList
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
Tooltip
>
</
When
>
...
...
@@ -352,7 +351,7 @@ class LiveCourseList extends React.Component {
</
Otherwise
>
</
Choose
>
</
div
>
)
)
;
},
},
{
...
...
@@ -426,7 +425,7 @@ class LiveCourseList extends React.Component {
key=
'share'
className=
'operate__item'
onClick=
{
()
=>
{
this
.
handleShowShareModal
(
item
)
this
.
handleShowShareModal
(
item
)
;
}
}
>
分享
</
div
>
...
...
@@ -456,10 +455,10 @@ class LiveCourseList extends React.Component {
</
div
>
)
}
</
div
>
)
)
;
},
},
]
]
;
}
else
{
columns
=
[
{
...
...
@@ -468,13 +467,13 @@ class LiveCourseList extends React.Component {
key
:
'course'
,
dataIndex
:
'courseName'
,
render
:
(
val
,
record
)
=>
{
let
hasCover
=
false
let
hasCover
=
false
;
return
(
<
div
className=
'record__item'
>
{
record
.
courseMediaVOS
.
map
((
item
,
index
)
=>
{
if
(
item
.
contentType
===
'COVER'
)
{
hasCover
=
true
return
<
img
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>
hasCover
=
true
;
return
<
img
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>
;
}
})
}
{
!
hasCover
&&
<
img
className=
'course-cover'
src=
{
'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'
}
alt=
''
/>
}
...
...
@@ -519,7 +518,7 @@ class LiveCourseList extends React.Component {
<
span
>
{
item
.
adminName
}
{
index
<
record
.
admins
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
span
>
</
Tooltip
>
...
...
@@ -532,7 +531,7 @@ class LiveCourseList extends React.Component {
<
span
>
{
item
.
adminName
}
{
index
<
record
.
admins
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
span
>
</
Otherwise
>
...
...
@@ -541,7 +540,7 @@ class LiveCourseList extends React.Component {
</
div
>
</
div
>
</
div
>
)
)
;
},
},
{
...
...
@@ -550,7 +549,7 @@ class LiveCourseList extends React.Component {
key
:
'couseCatalog'
,
dataIndex
:
'couseCatalog'
,
render
:
(
val
,
item
)
=>
{
return
<
div
className=
'categoryName'
>
{
item
.
categorySonName
}
</
div
>
return
<
div
className=
'categoryName'
>
{
item
.
categorySonName
}
</
div
>
;
},
},
{
...
...
@@ -566,11 +565,11 @@ class LiveCourseList extends React.Component {
this
.
setState
({
editData
:
item
,
openCoursewareModal
:
true
,
})
})
;
}
}
>
{
item
.
courseDocumentCount
}
个
</
span
>
)
)
;
},
},
{
...
...
@@ -583,11 +582,11 @@ class LiveCourseList extends React.Component {
<
span
className=
'iconfont icon quota-icon'
onClick=
{
()
=>
{
this
.
handleLinkToClassData
(
item
)
this
.
handleLinkToClassData
(
item
)
;
}
}
>

</
span
>
)
)
;
},
},
{
...
...
@@ -597,7 +596,7 @@ class LiveCourseList extends React.Component {
dataIndex
:
'created'
,
sorter
:
true
,
render
:
(
val
,
item
)
=>
{
return
<
span
>
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>
return
<
span
>
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>
;
},
},
{
...
...
@@ -616,7 +615,7 @@ class LiveCourseList extends React.Component {
<
span
>
{
item
.
planName
}
{
index
<
record
.
relatedPlanList
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
)
;
})
}
</
Tooltip
>
</
When
>
...
...
@@ -625,36 +624,36 @@ class LiveCourseList extends React.Component {
</
Otherwise
>
</
Choose
>
</
div
>
)
)
;
},
},
]
]
;
}
this
.
setState
({
columns
})
}
this
.
setState
({
columns
})
;
}
;
handleAdminName
=
(
adminArray
)
=>
{
let
adminStr
=
''
let
adminStr
=
''
;
adminArray
.
forEach
((
item
,
index
)
=>
{
if
(
index
<
adminArray
.
length
-
1
)
{
adminStr
=
adminStr
+
item
.
adminName
+
'、'
adminStr
=
adminStr
+
item
.
adminName
+
'、'
;
}
else
{
adminStr
=
adminStr
+
item
.
adminName
adminStr
=
adminStr
+
item
.
adminName
;
}
})
return
adminStr
}
})
;
return
adminStr
;
}
;
handlePlanName
=
(
planArray
)
=>
{
let
planStr
=
''
let
planStr
=
''
;
planArray
.
forEach
((
item
,
index
)
=>
{
if
(
index
<
planArray
.
length
-
1
)
{
planStr
=
planStr
+
item
.
planName
+
'、'
planStr
=
planStr
+
item
.
planName
+
'、'
;
}
else
{
planStr
=
planStr
+
item
.
planName
planStr
=
planStr
+
item
.
planName
;
}
})
return
planStr
}
})
;
return
planStr
;
}
;
renderMoreOperate
=
(
item
)
=>
{
let
now
=
new
Date
().
getTime
()
...
...
@@ -721,7 +720,7 @@ class LiveCourseList extends React.Component {
<
div
className=
'live-course-more-menu'
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleRelatedModalShow
(
item
)
}
>
关联培训
计划
关联培训
任务
</
div
>
)
}
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
toEditCoursePage
(
item
)
}
>
...
...
@@ -746,10 +745,10 @@ class LiveCourseList extends React.Component {
width
:
440
,
height
:
188
,
onOk
:
()
=>
{
this
.
deleteConfirm
(
record
)
this
.
deleteConfirm
(
record
)
;
},
})
}
})
;
}
;
deleteConfirm
=
(
item
)
=>
{
const
params
=
{
liveCourseId
:
item
.
liveCourseId
,
...
...
@@ -785,8 +784,8 @@ class LiveCourseList extends React.Component {
};
refreshCourseList
=
()
=>
{
this
.
props
.
onChange
(
this
.
props
.
query
)
}
this
.
props
.
onChange
(
this
.
props
.
query
)
;
}
;
//进入直播间
handleEnterLiveRoom
=
(
item
)
=>
{
if
(
item
.
thirdPartType
===
"WECHAT"
)
{
...
...
@@ -844,48 +843,48 @@ class LiveCourseList extends React.Component {

</
span
>
),
})
})
;
}
else
{
CourseService
.
getLiveCloudCourseDetail
({
liveCourseId
:
item
.
liveCourseId
,
}).
then
((
res
)
=>
{
const
url
=
`xmqx://liveCourseId=
${
item
.
liveCourseId
}
`
const
url
=
`xmqx://liveCourseId=
${
item
.
liveCourseId
}
`
;
if
(
res
.
result
.
courseState
===
'FINISH'
)
{
Modal
.
warning
({
title
:
'刷新页面'
,
icon
:
<
QuestionCircleOutlined
/>,
content
:
'课次已结束,请刷新一下'
,
onOk
:
()
=>
{
this
.
refreshCourseList
()
this
.
refreshCourseList
()
;
},
})
})
;
}
else
{
this
.
setState
({
url
,
openDownloadModal
:
true
})
this
.
setState
({
url
,
openDownloadModal
:
true
})
;
}
})
})
;
}
}
}
;
onShowSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
return
;
}
let
_query
=
this
.
props
.
query
_query
.
size
=
size
this
.
props
.
onChange
(
_query
)
}
let
_query
=
this
.
props
.
query
;
_query
.
size
=
size
;
this
.
props
.
onChange
(
_query
)
;
}
;
getDownloadVersion
()
{
const
isMac
=
/macintosh|mac os x/i
.
test
(
navigator
.
userAgent
)
const
isMac
=
/macintosh|mac os x/i
.
test
(
navigator
.
userAgent
)
;
// 判断学员系统
let
platform
let
platform
;
if
(
!
isMac
)
{
platform
=
1
platform
=
1
;
}
else
{
platform
=
4
platform
=
4
;
}
BaseService
.
getLastedVersion
({
model
:
5
,
platform
}).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
this
.
setState
({
downloadUrl
:
result
.
releaseUrl
})
})
const
{
result
=
{}
}
=
res
;
this
.
setState
({
downloadUrl
:
result
.
releaseUrl
})
;
})
;
}
handleViewPlayBack
=
(
item
)
=>
{
if
(
item
.
thirdPartType
===
"WECHAT"
)
{
...
...
@@ -917,78 +916,79 @@ class LiveCourseList extends React.Component {
}
let
htmlUrl
;
if
(
item
.
teacherId
===
User
.
getUserId
())
{
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?teacherId=
${
User
.
getUserId
()}
&id=
${
User
.
getStoreId
()}
`
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?teacherId=
${
User
.
getUserId
()}
&id=
${
User
.
getStoreId
()}
`
;
}
else
if
(
_
.
pluck
(
item
.
admins
,
'adminId'
).
includes
(
User
.
getUserId
()))
{
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?userId=
${
User
.
getUserId
()}
&id=
${
User
.
getStoreId
()}
`
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?userId=
${
User
.
getUserId
()}
&id=
${
User
.
getStoreId
()}
`
;
}
else
{
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?id=
${
User
.
getStoreId
()}
`
htmlUrl
=
`
${
LIVE_SHARE
}
replay/
${
item
.
liveCourseId
}
?id=
${
User
.
getStoreId
()}
`
;
}
window
.
open
(
htmlUrl
)
}
window
.
open
(
htmlUrl
)
;
}
;
handleRelatedModalShow
=
(
item
)
=>
{
const
selectPlanList
=
{}
const
selectPlanList
=
{}
;
if
(
item
.
relatedPlanList
)
{
item
.
relatedPlanList
.
map
((
i
tem
,
index
)
=>
{
selectPlanList
[
item
.
planId
]
=
{}
selectPlanList
[
item
.
planId
].
planId
=
item
.
planId
selectPlanList
[
item
.
planId
].
taskBaseVOList
=
[{
taskId
:
item
.
taskId
}]
return
item
})
item
.
relatedPlanList
.
map
((
childI
tem
,
index
)
=>
{
selectPlanList
[
childItem
.
taskId
]
=
{};
selectPlanList
[
childItem
.
taskId
].
taskId
=
childItem
.
taskId
;
selectPlanList
[
childItem
.
taskId
].
taskBaseVOList
=
[{
stageId
:
childItem
.
stageId
}];
return
item
;
})
;
}
this
.
setState
({
RelatedPlanModalVisible
:
true
,
selectCourseId
:
item
.
liveCourseId
,
selectPlanList
:
selectPlanList
,
})
}
})
;
}
;
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
})
}
})
;
}
;
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
console
.
log
(
'selectPlanList'
,
selectPlanList
);
this
.
setState
({
selectPlanList
:
selectPlanList
,
})
}
})
;
}
;
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
()
this
.
props
.
onChange
()
;
}
)
}
)
;
}
;
handleChangeTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
const
{
query
}
=
this
.
props
let
_columnKey
let
_order
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
this
.
props
;
let
_columnKey
;
let
_order
;
// 按创建时间升序排序
if
(
columnKey
===
'created'
&&
order
===
'ascend'
)
{
_columnKey
=
'CREATED'
_order
=
'SORT_ASC'
_columnKey
=
'CREATED'
;
_order
=
'SORT_ASC'
;
}
// 按创建时间降序排序
if
(
columnKey
===
'created'
&&
order
===
'descend'
)
{
_columnKey
=
'CREATED'
_order
=
'SORT_DESC'
_columnKey
=
'CREATED'
;
_order
=
'SORT_DESC'
;
}
const
_query
=
{
...
query
,
sortMap
:
{},
}
_query
.
sortMap
[
_columnKey
]
=
_order
this
.
props
.
onChange
(
_query
)
}
}
;
_query
.
sortMap
[
_columnKey
]
=
_order
;
this
.
props
.
onChange
(
_query
)
;
}
;
render
()
{
const
{
total
,
query
,
courseList
,
loading
}
=
this
.
props
const
{
current
,
size
}
=
query
const
{
openDownloadModal
,
downloadUrl
,
url
,
columns
,
openCoursewareModal
,
editData
,
RelatedPlanModalVisible
,
selectCourseId
,
selectPlanList
}
=
this
.
state
const
{
match
}
=
this
.
props
const
{
total
,
query
,
courseList
,
loading
}
=
this
.
props
;
const
{
current
,
size
}
=
query
;
const
{
openDownloadModal
,
downloadUrl
,
url
,
columns
,
openCoursewareModal
,
editData
,
RelatedPlanModalVisible
,
selectCourseId
,
selectPlanList
}
=
this
.
state
;
const
{
match
}
=
this
.
props
;
return
(
<
div
className=
'live-course-list'
>
...
...
@@ -1014,8 +1014,8 @@ class LiveCourseList extends React.Component {
pageSize=
{
size
}
total=
{
parseInt
(
total
)
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
query
,
current
:
page
+
1
}
this
.
props
.
onChange
(
_query
)
const
_query
=
{
...
query
,
current
:
page
+
1
}
;
this
.
props
.
onChange
(
_query
)
;
}
}
onShowSizeChange=
{
this
.
onShowSizeChange
}
/>
...
...
@@ -1026,8 +1026,8 @@ class LiveCourseList extends React.Component {
<
ManageCoursewareModal
data=
{
editData
}
onCancel=
{
()
=>
{
this
.
props
.
onChange
()
this
.
setState
({
openCoursewareModal
:
false
})
this
.
props
.
onChange
()
;
this
.
setState
({
openCoursewareModal
:
false
})
;
}
}
/>
)
}
...
...
@@ -1038,7 +1038,7 @@ class LiveCourseList extends React.Component {
this
.
setState
({
url
:
''
,
openDownloadModal
:
false
,
})
})
;
}
}
/>
)
}
...
...
@@ -1055,8 +1055,8 @@ class LiveCourseList extends React.Component {
<
iframe
src=
{
url
}
style=
{
{
display
:
'none'
}
}
title=
'navigation'
/>
<
Route
path=
{
`${match.url}/live-course-data`
}
component=
{
DataList
}
/>
</
div
>
)
)
;
}
}
export
default
withRouter
(
LiveCourseList
)
export
default
withRouter
(
LiveCourseList
)
;
src/modules/course-manage/graphics-course/components/GraphicsCourseList.jsx
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-08-05 10:12:45
* @LastEditors:
yuananting
* @LastEditTime: 2021-0
7-15 14:12
:29
* @LastEditors:
wufan
* @LastEditTime: 2021-0
9-03 10:36
:29
* @Description: 线上课-列表模块
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
import
User
from
'@/common/js/user'
import
college
from
'@/common/lottie/college'
import
{
PageControl
,
XMTable
}
from
'@/components'
import
{
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
import
CourseService
from
'@/domains/course-domain/CourseService'
import
ShareLiveModal
from
'@/modules/course-manage/modal/ShareLiveModal'
import
{
Dropdown
,
message
,
Modal
,
Switch
,
Tooltip
}
from
'antd'
import
React
from
'react'
import
RelatedPlanModal
from
'../../modal/RelatedPlanModal'
import
WatchDataModal
from
'../modal/WatchDataModal'
import
'./GraphicsCourseList.less'
import
User
from
'@/common/js/user'
;
import
college
from
'@/common/lottie/college'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
{
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
ShareLiveModal
from
'@/modules/course-manage/modal/ShareLiveModal'
;
import
{
Dropdown
,
message
,
Modal
,
Switch
,
Tooltip
}
from
'antd'
;
import
React
from
'react'
;
import
RelatedPlanModal
from
'../../modal/RelatedPlanModal'
;
import
WatchDataModal
from
'../modal/WatchDataModal'
;
import
'./GraphicsCourseList.less'
;
const
defaultCoverUrl
=
'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'
const
defaultCoverUrl
=
'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'
;
class
GraphicsCourseList
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
)
this
.
state
=
{
id
:
''
,
// 视频课ID
studentIds
:
[],
RelatedPlanModalVisible
:
false
,
selectPlanList
:
{},
}
}
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
id
:
''
,
// 视频课ID
studentIds
:
[],
RelatedPlanModalVisible
:
false
,
selectPlanList
:
{},
};
}
componentDidMount
()
{
const
videoCourseItem
=
localStorage
.
getItem
(
'videoCourseItem'
)
if
(
videoCourseItem
)
{
const
_videoCourseItem
=
JSON
.
parse
(
videoCourseItem
)
this
.
handleShowShareModal
(
_videoCourseItem
,
true
)
}
}
componentDidMount
()
{
const
videoCourseItem
=
localStorage
.
getItem
(
'videoCourseItem'
);
if
(
videoCourseItem
)
{
const
_videoCourseItem
=
JSON
.
parse
(
videoCourseItem
);
this
.
handleShowShareModal
(
_videoCourseItem
,
true
);
}
}
// 观看数据弹窗
handleShowWatchDataModal
=
(
record
)
=>
{
const
watchDataModal
=
(
<
WatchDataModal
type=
'videoCourseList'
data=
{
record
}
close=
{
()
=>
{
this
.
setState
({
watchDataModal
:
null
,
})
}
}
/>
)
this
.
setState
({
watchDataModal
})
}
// 观看数据弹窗
handleShowWatchDataModal
=
(
record
)
=>
{
const
watchDataModal
=
(
<
WatchDataModal
type=
'videoCourseList'
data=
{
record
}
close=
{
()
=>
{
this
.
setState
({
watchDataModal
:
null
,
});
}
}
/>
);
this
.
setState
({
watchDataModal
});
};
handlePlanName
=
(
planArray
)
=>
{
let
planStr
=
''
planArray
.
forEach
((
item
,
index
)
=>
{
if
(
index
<
planArray
.
length
-
1
)
{
planStr
=
planStr
+
item
.
planName
+
'、'
}
else
{
planStr
=
planStr
+
item
.
planName
}
})
return
planStr
}
// 请求表头
parseColumns
=
()
=>
{
const
columns
=
[
{
title
:
'图文课'
,
key
:
'scheduleName'
,
dataIndex
:
'scheduleName'
,
width
:
321
,
fixed
:
'left'
,
render
:
(
val
,
record
)
=>
{
const
{
coverUrl
}
=
record
return
(
<
div
className=
'record__item'
>
{
/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */
}
<
img
className=
'course-cover'
src=
{
coverUrl
||
defaultCoverUrl
}
alt=
''
/>
<
Choose
>
<
When
condition=
{
record
.
courseName
.
length
>
25
}
>
<
Tooltip
title=
{
record
.
courseName
}
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
Tooltip
>
</
When
>
<
Otherwise
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
Otherwise
>
</
Choose
>
</
div
>
)
},
},
{
title
:
'课程分类'
,
key
:
'categoryName'
,
dataIndex
:
'categoryName'
,
width
:
120
,
render
:
(
val
,
record
)
=>
{
return
<
div
className=
'record__item'
>
{
record
.
categorySonName
}
</
div
>
},
},
{
title
:
'创建人'
,
key
:
'createName'
,
dataIndex
:
'createName'
,
width
:
100
,
render
:
(
val
)
=>
{
return
(
<
div
>
{
val
&&
(
<
Tooltip
title=
{
val
}
>
<
div
>
{
val
.
length
>
4
?
`${val.slice(0, 4)}
...
`
:
val
}
</
div
>
</
Tooltip
>
)
}
</
div
>
)
},
},
{
title
:
(
<
span
>
<
span
>
学院展示
</
span
>
<
Tooltip
title=
{
<
div
>
开启后,学员可在学院内查看到此课程。
<
br
/>
关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。
</
div
>
}
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
}
}
>

</
i
>
</
Tooltip
>
</
span
>
),
width
:
120
,
dataIndex
:
'courseware'
,
render
:
(
val
,
item
,
index
)
=>
{
return
(
<
Switch
size=
'small'
checked=
{
item
.
shelfState
===
'YES'
}
defaultChecked=
{
item
.
shelfState
===
'YES'
?
true
:
false
}
onChange=
{
(
checked
)
=>
this
.
changeShelfState
(
index
,
item
,
checked
)
}
/>
)
},
},
{
title
:
'观看学员数'
,
width
:
110
,
key
:
'watchUserCount'
,
dataIndex
:
'watchUserCount'
,
render
:
(
val
,
item
)
=>
{
return
<
div
className=
'watchUserCount'
>
{
val
}
</
div
>
},
},
{
title
:
'创建时间'
,
width
:
181
,
key
:
'created'
,
dataIndex
:
'created'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
},
},
{
title
:
'最近修改时间'
,
width
:
181
,
key
:
'updated'
,
dataIndex
:
'updated'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
},
},
{
title
:
'关联项'
,
width
:
200
,
key
:
'planList'
,
dataIndex
:
'planList'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'related-task'
>
<
Choose
>
<
When
condition=
{
record
.
relatedPlanList
}
>
<
Tooltip
title=
{
this
.
handlePlanName
(
record
.
relatedPlanList
)
}
placement=
'top'
arrowPointAtCenter
>
{
record
.
relatedPlanList
.
map
((
item
,
index
)
=>
{
return
(
<
span
key=
{
item
.
plan
Id
}
>
{
item
.
planName
}
{
index
<
record
.
relatedPlanList
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
)
})
}
</
Tooltip
>
</
When
>
<
Otherwise
>
<
span
></
span
>
</
Otherwise
>
</
Choose
>
</
div
>
)
},
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
width
:
210
,
fixed
:
'right'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'operate'
>
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleShowWatchDataModal
(
record
)
}
>
观看数据
</
div
>
<
span
className=
'operate__item split'
>
|
</
span
>
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleShowShareModal
(
record
)
}
>
分享
</
div
>
<
span
className=
'operate__item split'
>
|
</
span
>
<
Dropdown
overlay=
{
this
.
renderMoreOperate
(
record
)
}
>
<
span
className=
'more-operate'
>
<
span
className=
'operate-text'
>
更多
</
span
>
<
span
className=
'iconfont icon'
style=
{
{
color
:
'#2966FF'
}
}
>

</
span
>
</
span
>
</
Dropdown
>
</
div
>
)
},
},
]
return
columns
}
handlePlanName
=
(
planArray
)
=>
{
let
planStr
=
''
;
planArray
.
forEach
((
item
,
index
)
=>
{
if
(
index
<
planArray
.
length
-
1
)
{
planStr
=
planStr
+
item
.
planName
+
'、'
;
}
else
{
planStr
=
planStr
+
item
.
planName
;
}
});
return
planStr
;
};
// 请求表头
parseColumns
=
()
=>
{
const
columns
=
[
{
title
:
'图文课'
,
key
:
'scheduleName'
,
dataIndex
:
'scheduleName'
,
width
:
321
,
fixed
:
'left'
,
render
:
(
val
,
record
)
=>
{
const
{
coverUrl
}
=
record
;
return
(
<
div
className=
'record__item'
>
{
/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */
}
<
img
className=
'course-cover'
src=
{
coverUrl
||
defaultCoverUrl
}
alt=
''
/>
<
Choose
>
<
When
condition=
{
record
.
courseName
.
length
>
25
}
>
<
Tooltip
title=
{
record
.
courseName
}
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
Tooltip
>
</
When
>
<
Otherwise
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
Otherwise
>
</
Choose
>
</
div
>
);
},
},
{
title
:
'课程分类'
,
key
:
'categoryName'
,
dataIndex
:
'categoryName'
,
width
:
120
,
render
:
(
val
,
record
)
=>
{
return
<
div
className=
'record__item'
>
{
record
.
categorySonName
}
</
div
>;
},
},
{
title
:
'创建人'
,
key
:
'createName'
,
dataIndex
:
'createName'
,
width
:
100
,
render
:
(
val
)
=>
{
return
(
<
div
>
{
val
&&
(
<
Tooltip
title=
{
val
}
>
<
div
>
{
val
.
length
>
4
?
`${val.slice(0, 4)}
...
`
:
val
}
</
div
>
</
Tooltip
>
)
}
</
div
>
);
},
},
{
title
:
(
<
span
>
<
span
>
学院展示
</
span
>
<
Tooltip
title=
{
<
div
>
开启后,学员可在学院内查看到此课程。
<
br
/>
关闭后,学院内不再展示此课程,但学员仍可通过分享的海报/链接查看此课程。
</
div
>
}
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
}
}
>

</
i
>
</
Tooltip
>
</
span
>
),
width
:
120
,
dataIndex
:
'courseware'
,
render
:
(
val
,
item
,
index
)
=>
{
return
(
<
Switch
size=
'small'
checked=
{
item
.
shelfState
===
'YES'
}
defaultChecked=
{
item
.
shelfState
===
'YES'
?
true
:
false
}
onChange=
{
(
checked
)
=>
this
.
changeShelfState
(
index
,
item
,
checked
)
}
/>
);
},
},
{
title
:
'观看学员数'
,
width
:
110
,
key
:
'watchUserCount'
,
dataIndex
:
'watchUserCount'
,
render
:
(
val
,
item
)
=>
{
return
<
div
className=
'watchUserCount'
>
{
val
}
</
div
>;
},
},
{
title
:
'创建时间'
,
width
:
181
,
key
:
'created'
,
dataIndex
:
'created'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
);
},
},
{
title
:
'最近修改时间'
,
width
:
181
,
key
:
'updated'
,
dataIndex
:
'updated'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
);
},
},
{
title
:
'关联项'
,
width
:
200
,
key
:
'planList'
,
dataIndex
:
'planList'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'related-task'
>
<
Choose
>
<
When
condition=
{
record
.
relatedPlanList
}
>
<
Tooltip
title=
{
this
.
handlePlanName
(
record
.
relatedPlanList
)
}
placement=
'top'
arrowPointAtCenter
>
{
record
.
relatedPlanList
.
map
((
item
,
index
)
=>
{
return
(
<
span
key=
{
item
.
task
Id
}
>
{
item
.
planName
}
{
index
<
record
.
relatedPlanList
.
length
-
1
&&
<
span
>
、
</
span
>
}{
' '
}
</
span
>
);
})
}
</
Tooltip
>
</
When
>
<
Otherwise
>
<
span
></
span
>
</
Otherwise
>
</
Choose
>
</
div
>
);
},
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
width
:
210
,
fixed
:
'right'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'operate'
>
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleShowWatchDataModal
(
record
)
}
>
观看数据
</
div
>
<
span
className=
'operate__item split'
>
|
</
span
>
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleShowShareModal
(
record
)
}
>
分享
</
div
>
<
span
className=
'operate__item split'
>
|
</
span
>
<
Dropdown
overlay=
{
this
.
renderMoreOperate
(
record
)
}
>
<
span
className=
'more-operate'
>
<
span
className=
'operate-text'
>
更多
</
span
>
<
span
className=
'iconfont icon'
style=
{
{
color
:
'#2966FF'
}
}
>

</
span
>
</
span
>
</
Dropdown
>
</
div
>
);
},
},
];
return
columns
;
};
handleRelatedModalShow
=
(
item
)
=>
{
const
selectPlanList
=
{}
if
(
item
.
relatedPlanList
)
{
item
.
relatedPlanList
.
map
((
i
tem
,
index
)
=>
{
selectPlanList
[
item
.
planId
]
=
{}
selectPlanList
[
item
.
planId
].
planId
=
item
.
planId
selectPlanList
[
item
.
planId
].
taskBaseVOList
=
[{
taskId
:
item
.
taskId
}]
return
item
})
}
handleRelatedModalShow
=
(
item
)
=>
{
const
selectPlanList
=
{};
if
(
item
.
relatedPlanList
)
{
item
.
relatedPlanList
.
map
((
childI
tem
,
index
)
=>
{
selectPlanList
[
childItem
.
taskId
]
=
{};
selectPlanList
[
childItem
.
taskId
].
taskId
=
childItem
.
taskId
;
selectPlanList
[
childItem
.
taskId
].
taskBaseVOList
=
[{
stageId
:
childItem
.
stageId
}];
return
item
;
});
}
this
.
setState
({
RelatedPlanModalVisible
:
true
,
selectCourseId
:
item
.
id
,
selectPlanList
:
selectPlanList
,
})
}
this
.
setState
({
RelatedPlanModalVisible
:
true
,
selectCourseId
:
item
.
id
,
selectPlanList
:
selectPlanList
,
});
};
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
})
}
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
});
};
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
this
.
setState
({
selectPlanList
:
selectPlanList
,
})
}
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
this
.
setState
({
selectPlanList
:
selectPlanList
,
});
};
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
()
}
)
}
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
();
}
);
};
renderMoreOperate
=
(
item
)
=>
{
return
(
<
div
className=
'live-course-more-menu'
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<
div
className=
'operate__item'
key=
'plan'
onClick=
{
()
=>
{
this
.
handleRelatedModalShow
(
item
)
}
}
>
关联培训计划
</
div
>
)
}
<
div
className=
'operate__item'
key=
'edit'
onClick=
{
()
=>
{
window
.
RCHistory
.
push
(
`/create-graphics-course?type=edit&id=${item.id}`
)
}
}
>
编辑
</
div
>
<
div
className=
'operate__item'
key=
'delete'
onClick=
{
()
=>
this
.
handleDeleteGraphicsCourse
(
item
.
id
)
}
>
删除
</
div
>
</
div
>
)
}
//改变上架状态
changeShelfState
=
(
index
,
item
,
checked
)
=>
{
let
_shelfState
=
checked
?
'YES'
:
'NO'
const
params
=
{
courseId
:
item
.
id
,
shelfState
:
_shelfState
,
}
CourseService
.
changeVideoShelfState
(
params
).
then
((
res
)
=>
{
if
(
res
.
success
)
{
if
(
_shelfState
===
'YES'
)
{
message
.
success
(
'已开启展示'
)
}
else
{
message
.
success
(
'已取消展示'
)
}
this
.
props
.
changeShelfState
(
index
,
_shelfState
)
}
})
}
// 删除视频课
handleDeleteGraphicsCourse
=
(
scheduleId
)
=>
{
Modal
.
confirm
({
title
:
'你确定要删除此线上课吗?'
,
content
:
'删除后,学员将不能进行观看。'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
okText
:
'确定'
,
okType
:
'danger'
,
cancelText
:
'取消'
,
onOk
:
()
=>
{
const
param
=
{
courseId
:
scheduleId
,
storeId
:
User
.
getStoreId
(),
}
CourseService
.
delVideoSchedule
(
param
).
then
(()
=>
{
message
.
success
(
'删除成功'
)
this
.
props
.
onChange
()
})
},
})
}
renderMoreOperate
=
(
item
)
=>
{
return
(
<
div
className=
'live-course-more-menu'
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<
div
className=
'operate__item'
key=
'plan'
onClick=
{
()
=>
{
this
.
handleRelatedModalShow
(
item
);
}
}
>
关联培训任务
</
div
>
)
}
<
div
className=
'operate__item'
key=
'edit'
onClick=
{
()
=>
{
window
.
RCHistory
.
push
(
`/create-graphics-course?type=edit&id=${item.id}`
);
}
}
>
编辑
</
div
>
<
div
className=
'operate__item'
key=
'delete'
onClick=
{
()
=>
this
.
handleDeleteGraphicsCourse
(
item
.
id
)
}
>
删除
</
div
>
</
div
>
);
};
//改变上架状态
changeShelfState
=
(
index
,
item
,
checked
)
=>
{
let
_shelfState
=
checked
?
'YES'
:
'NO'
;
const
params
=
{
courseId
:
item
.
id
,
shelfState
:
_shelfState
,
};
CourseService
.
changeVideoShelfState
(
params
).
then
((
res
)
=>
{
if
(
res
.
success
)
{
if
(
_shelfState
===
'YES'
)
{
message
.
success
(
'已开启展示'
);
}
else
{
message
.
success
(
'已取消展示'
);
}
this
.
props
.
changeShelfState
(
index
,
_shelfState
);
}
});
};
// 删除视频课
handleDeleteGraphicsCourse
=
(
scheduleId
)
=>
{
Modal
.
confirm
({
title
:
'你确定要删除此线上课吗?'
,
content
:
'删除后,学员将不能进行观看。'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
okText
:
'确定'
,
okType
:
'danger'
,
cancelText
:
'取消'
,
onOk
:
()
=>
{
const
param
=
{
courseId
:
scheduleId
,
storeId
:
User
.
getStoreId
(),
};
CourseService
.
delVideoSchedule
(
param
).
then
(()
=>
{
message
.
success
(
'删除成功'
);
this
.
props
.
onChange
();
});
},
});
};
// 显示分享弹窗
handleShowShareModal
=
(
record
,
needStr
=
false
)
=>
{
const
{
id
,
scheduleVideoUrl
}
=
record
const
htmlUrl
=
`
${
LIVE_SHARE
}
graphics_detail/
${
id
}
?id=
${
User
.
getStoreId
()}
`
const
longUrl
=
htmlUrl
const
{
coverUrl
,
courseName
}
=
record
const
shareData
=
{
longUrl
,
coverUrl
,
scheduleVideoUrl
,
courseName
,
}
// 显示分享弹窗
handleShowShareModal
=
(
record
,
needStr
=
false
)
=>
{
const
{
id
,
scheduleVideoUrl
}
=
record
;
const
htmlUrl
=
`
${
LIVE_SHARE
}
graphics_detail/
${
id
}
?id=
${
User
.
getStoreId
()}
`
;
const
longUrl
=
htmlUrl
;
const
{
coverUrl
,
courseName
}
=
record
;
const
shareData
=
{
longUrl
,
coverUrl
,
scheduleVideoUrl
,
courseName
,
};
const
shareLiveModal
=
(
<
ShareLiveModal
needStr=
{
needStr
}
data=
{
shareData
}
type=
'graphicsClass'
title=
'图文课'
close=
{
()
=>
{
this
.
setState
({
shareLiveModal
:
null
,
})
localStorage
.
setItem
(
'videoCourseItem'
,
''
)
}
}
/>
)
const
shareLiveModal
=
(
<
ShareLiveModal
needStr=
{
needStr
}
data=
{
shareData
}
type=
'graphicsClass'
title=
'图文课'
close=
{
()
=>
{
this
.
setState
({
shareLiveModal
:
null
,
});
localStorage
.
setItem
(
'videoCourseItem'
,
''
);
}
}
/>
);
this
.
setState
({
shareLiveModal
})
}
this
.
setState
({
shareLiveModal
});
};
handleChangeTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
const
{
query
}
=
this
.
props
let
{
order
:
_order
}
=
query
// 按创建时间升序排序
if
(
columnKey
===
'created'
&&
order
===
'ascend'
)
{
_order
=
'CREATED_ASC'
}
// 按创建时间降序排序
if
(
columnKey
===
'created'
&&
order
===
'descend'
)
{
_order
=
'CREATED_DESC'
}
// 按更新时间升序排序
if
(
columnKey
===
'updated'
&&
order
===
'ascend'
)
{
_order
=
'UPDATED_ASC'
}
// 按更新时间降序排序
if
(
columnKey
===
'updated'
&&
order
===
'descend'
)
{
_order
=
'UPDATED_DESC'
}
handleChangeTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
this
.
props
;
let
{
order
:
_order
}
=
query
;
// 按创建时间升序排序
if
(
columnKey
===
'created'
&&
order
===
'ascend'
)
{
_order
=
'CREATED_ASC'
;
}
// 按创建时间降序排序
if
(
columnKey
===
'created'
&&
order
===
'descend'
)
{
_order
=
'CREATED_DESC'
;
}
// 按更新时间升序排序
if
(
columnKey
===
'updated'
&&
order
===
'ascend'
)
{
_order
=
'UPDATED_ASC'
;
}
// 按更新时间降序排序
if
(
columnKey
===
'updated'
&&
order
===
'descend'
)
{
_order
=
'UPDATED_DESC'
;
}
const
_query
=
{
...
query
,
orderEnum
:
_order
,
}
this
.
props
.
onChange
(
_query
)
}
handleRelatedModalShow
=
(
item
)
=>
{
const
selectPlanList
=
{}
if
(
item
.
relatedPlanList
)
{
item
.
relatedPlanList
.
map
((
item
,
index
)
=>
{
selectPlanList
[
item
.
planId
]
=
{}
selectPlanList
[
item
.
planId
].
planId
=
item
.
planId
selectPlanList
[
item
.
planId
].
taskBaseVOList
=
[{
taskId
:
item
.
taskId
}]
return
item
})
}
this
.
setState
({
RelatedPlanModalVisible
:
true
,
selectCourseId
:
item
.
id
,
selectPlanList
:
selectPlanList
,
})
}
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
})
}
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
this
.
setState
({
selectPlanList
:
selectPlanList
,
})
}
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
()
}
)
}
render
()
{
const
{
RelatedPlanModalVisible
,
selectCourseId
,
selectPlanList
}
=
this
.
state
const
{
dataSource
=
[],
totalCount
,
query
}
=
this
.
props
const
{
current
,
size
}
=
query
const
_query
=
{
...
query
,
orderEnum
:
_order
,
};
this
.
props
.
onChange
(
_query
);
};
return
(
<
div
className=
'video-course-list'
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
dataSource
}
columns=
{
this
.
parseColumns
()
}
onChange=
{
this
.
handleChangeTable
}
pagination=
{
false
}
scroll=
{
{
x
:
1500
}
}
bordered
className=
'video-list-table'
/>
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
});
};
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
this
.
setState
({
selectPlanList
:
selectPlanList
,
});
};
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
();
}
);
};
render
()
{
const
{
RelatedPlanModalVisible
,
selectCourseId
,
selectPlanList
}
=
this
.
state
;
const
{
dataSource
=
[],
totalCount
,
query
}
=
this
.
props
;
const
{
current
,
size
}
=
query
;
<
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
>
{
RelatedPlanModalVisible
&&
(
<
RelatedPlanModal
onClose=
{
this
.
closeRelatedPlanModalVisible
}
visible=
{
RelatedPlanModalVisible
}
selectCourseId=
{
selectCourseId
}
selectPlanList=
{
selectPlanList
}
onChange=
{
this
.
onChangeSelectPlanList
}
onConfirm=
{
this
.
onConfirmSelectPlanList
}
/>
)
}
{
RelatedPlanModalVisible
&&
(
<
RelatedPlanModal
onClose=
{
this
.
closeRelatedPlanModalVisible
}
visible=
{
RelatedPlanModalVisible
}
selectCourseId=
{
selectCourseId
}
selectPlanList=
{
selectPlanList
}
onChange=
{
this
.
onChangeSelectPlanList
}
onConfirm=
{
this
.
onConfirmSelectPlanList
}
/>
)
}
{
this
.
state
.
shareLiveModal
}
{
this
.
state
.
watchDataModal
}
</
div
>
)
}
return
(
<
div
className=
'video-course-list'
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
dataSource
}
columns=
{
this
.
parseColumns
()
}
onChange=
{
this
.
handleChangeTable
}
pagination=
{
false
}
scroll=
{
{
x
:
1500
}
}
bordered
className=
'video-list-table'
/>
<
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
>
{
RelatedPlanModalVisible
&&
(
<
RelatedPlanModal
onClose=
{
this
.
closeRelatedPlanModalVisible
}
visible=
{
RelatedPlanModalVisible
}
selectCourseId=
{
selectCourseId
}
selectPlanList=
{
selectPlanList
}
onChange=
{
this
.
onChangeSelectPlanList
}
onConfirm=
{
this
.
onConfirmSelectPlanList
}
/>
)
}
{
this
.
state
.
shareLiveModal
}
{
this
.
state
.
watchDataModal
}
</
div
>
);
}
}
export
default
GraphicsCourseList
export
default
GraphicsCourseList
;
src/modules/course-manage/modal/RelatedPlanModal.jsx
View file @
b427be83
...
...
@@ -2,8 +2,8 @@ import User from '@/common/js/user';
import
college
from
'@/common/lottie/college'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
PlanService
from
'@/domains/plan-domain/plan
Service'
;
import
{
Input
,
Modal
}
from
'antd'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenter
Service'
;
import
{
Input
,
Modal
,
Tooltip
}
from
'antd'
;
import
React
from
'react'
;
import
_
from
'underscore'
;
import
'./RelatedPlanModal.less'
;
...
...
@@ -33,7 +33,7 @@ class RelatedPlanModal extends React.Component {
size
,
storeId
:
User
.
getStoreId
(),
};
PlanService
.
getStorePlan
All
(
params
).
then
((
res
)
=>
{
TaskCenterService
.
getStoreTask
All
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
...
...
@@ -65,11 +65,31 @@ class RelatedPlanModal extends React.Component {
);
};
renderTitle
=
()
=>
{
return
(
<
div
className=
'tip-title'
>
<
p
>
为了不影响学员学习,系统已对数据进行筛选
</
p
>
<
p
>
1、课程不能直接关联「已发布」的培训任务筛选;
</
p
>
<
p
>
2、一个课程不能重复出现在同一培训任务中
</
p
>
</
div
>
);
};
renderTableTitle
=
()
=>
{
return
(
<
div
>
<
Tooltip
title=
{
this
.
renderTitle
()
}
overlayClassName=
'table-title-tooltip'
>
培训任务
<
span
className=
'icon iconfont table-title'
>

</
span
>
</
Tooltip
>
</
div
>
);
};
// 请求表头
parsePlanColumns
=
()
=>
{
const
columns
=
[
{
title
:
'培训计划'
,
title
:
this
.
renderTableTitle
()
,
key
:
'planName'
,
dataIndex
:
'planName'
,
render
:
(
val
,
record
)
=>
{
...
...
@@ -93,38 +113,37 @@ class RelatedPlanModal extends React.Component {
];
return
columns
;
};
selectPlanList
=
(
record
,
selected
,
plan
Id
)
=>
{
selectPlanList
=
(
record
,
selected
,
task
Id
)
=>
{
const
{
selectPlanList
}
=
this
.
props
;
let
_selectPlanList
=
{
...
selectPlanList
};
if
(
selected
)
{
if
(
!
_selectPlanList
[
plan
Id
])
{
_selectPlanList
[
plan
Id
]
=
{};
if
(
!
_selectPlanList
[
task
Id
])
{
_selectPlanList
[
task
Id
]
=
{};
}
_selectPlanList
[
plan
Id
].
taskBaseVOList
=
[];
_selectPlanList
[
planId
].
planId
=
plan
Id
;
_selectPlanList
[
planId
].
taskBaseVOList
.
push
(
record
);
_selectPlanList
[
task
Id
].
taskBaseVOList
=
[];
_selectPlanList
[
taskId
].
taskId
=
task
Id
;
_selectPlanList
[
taskId
].
taskBaseVOList
.
push
({
...
record
,
stageId
:
record
.
taskId
}
);
}
else
{
if
(
!
_selectPlanList
[
plan
Id
])
{
_selectPlanList
[
plan
Id
]
=
{};
if
(
!
_selectPlanList
[
task
Id
])
{
_selectPlanList
[
task
Id
]
=
{};
}
_selectPlanList
[
plan
Id
].
taskBaseVOList
=
[];
_selectPlanList
[
planId
].
planId
=
plan
Id
;
_selectPlanList
[
task
Id
].
taskBaseVOList
=
[];
_selectPlanList
[
taskId
].
taskId
=
task
Id
;
}
this
.
props
.
onChange
(
_selectPlanList
);
// this.setState({selectPlanList:_selectPlanList});
};
handleSelectPlanListData
(
selectPlanList
)
{
let
_selectPlanList
=
[];
for
(
let
key
in
selectPlanList
)
{
let
item
=
{};
if
(
selectPlanList
[
key
].
taskBaseVOList
)
{
item
.
planId
=
selectPlanList
[
key
].
plan
Id
;
item
.
taskId
=
selectPlanList
[
key
].
task
Id
;
if
(
selectPlanList
[
key
].
taskBaseVOList
[
0
])
{
item
.
taskId
=
selectPlanList
[
key
].
taskBaseVOList
[
0
].
task
Id
;
item
.
stageId
=
selectPlanList
[
key
].
taskBaseVOList
[
0
].
stage
Id
;
}
}
if
(
item
.
task
Id
)
{
if
(
item
.
stage
Id
)
{
_selectPlanList
.
push
(
item
);
}
}
...
...
@@ -134,10 +153,10 @@ class RelatedPlanModal extends React.Component {
const
{
selectPlanList
}
=
this
.
props
;
const
params
=
{
courseId
:
this
.
props
.
selectCourseId
,
related
Plan
List
:
this
.
handleSelectPlanListData
(
selectPlanList
),
related
Task
List
:
this
.
handleSelectPlanListData
(
selectPlanList
),
storeId
:
User
.
getStoreId
(),
};
CourseService
.
relatedCourseToPlan
(
params
).
then
((
res
)
=>
{
TaskCenterService
.
relatedCourseToTask
(
params
).
then
((
res
)
=>
{
this
.
props
.
onConfirm
();
});
};
...
...
@@ -159,7 +178,7 @@ class RelatedPlanModal extends React.Component {
const
{
visible
,
selectPlanList
}
=
this
.
props
;
return
(
<
Modal
title=
'关联培训
计划
'
title=
'关联培训
任务
'
onCancel=
{
this
.
props
.
onClose
}
maskClosable=
{
false
}
visible=
{
visible
}
...
...
@@ -170,7 +189,7 @@ class RelatedPlanModal extends React.Component {
closeIcon=
{
<
span
className=
'icon iconfont modal-close-icon'
>

</
span
>
}
>
<
div
className=
'search-container'
>
<
Search
placeholder=
'搜索培训
计划
名称'
placeholder=
'搜索培训
任务
名称'
style=
{
{
width
:
207
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangePlanName
(
e
.
target
.
value
);
...
...
@@ -200,7 +219,7 @@ class RelatedPlanModal extends React.Component {
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
plan
Id
}
rowKey=
{
(
record
)
=>
record
.
task
Id
}
className=
'plan-table'
dataSource=
{
dataSource
}
columns=
{
this
.
parsePlanColumns
()
}
...
...
@@ -210,14 +229,12 @@ class RelatedPlanModal extends React.Component {
return
;
}
if
(
_record
.
taskBaseVOList
.
length
!==
0
)
{
const
selectPlan
=
selectPlanList
[
_record
.
plan
Id
];
const
selectPlan
=
selectPlanList
[
_record
.
task
Id
];
let
taskBaseVOList
=
[];
if
(
selectPlan
)
{
taskBaseVOList
=
selectPlan
.
taskBaseVOList
;
}
console
.
log
(
'taskBaseVOList'
,
taskBaseVOList
);
return
(
<
div
>
<
XMTable
...
...
@@ -232,9 +249,9 @@ class RelatedPlanModal extends React.Component {
className=
'child-table'
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
taskBaseVOList
,
'
task
Id'
),
selectedRowKeys
:
_
.
pluck
(
taskBaseVOList
,
'
stage
Id'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectPlanList
(
record
,
selected
,
_record
.
plan
Id
);
this
.
selectPlanList
(
record
,
selected
,
_record
.
task
Id
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{},
}
}
...
...
src/modules/course-manage/modal/RelatedPlanModal.less
View file @
b427be83
.related-plan-modal{
.search-container{
margin-bottom:16px;
.table-title-tooltip {
max-width: 600px!important;
}
.related-plan-modal {
.table-title {
margin-left: 8px;
margin-left: 5px;
cursor: pointer;
color: rgb(191, 191, 191);
font-size: 14px;
font-weight: normal;
}
.search-container {
margin-bottom: 16px;
}
.select-container {
margin-bottom: 12px;
.con {
background: #e9efff;
border-radius: 4px;
padding: 6px 16px;
display: inline-flex;
align-items: center;
justify-content: space-between;
.tip {
font-size: 14px;
color: #2966ff;
margin-right: 8px;
}
.text {
font-size: 14px;
color: #666;
margin-right: 30px;
}
.clear {
color: #2966ff;
font-size: 14px;
}
}
.select-container{
margin-bottom:12px;
.con{
background: #E9EFFF;
border-radius: 4px;
padding:6px 16px;
display: inline-flex;
align-items: center;
justify-content: space-between;
.tip{
font-size:14px;
color:#2966FF;
margin-right:8px;
}
.text{
font-size:14px;
color:#666;
margin-right:30px;
}
.clear{
color:#2966FF;
font-size:14px;
}
}
}
.plan-table {
.taskName {
color: #666666;
font-size: 14px;
}
.plan-table{
.taskName{
color:#666666;
font-size:14px;
}
.task-learn-percentage{
color:#666666;
font-size:14px;
.task-learn-percentage {
color: #666666;
font-size: 14px;
}
.course-info {
margin-left: 57px;
.course-type {
font-size: 11px;
color: #666666;
padding: 0px 6px;
line-height: 16px;
border: 1px solid #999999;
margin-right: 4px;
border-radius: 2px;
}
.course-name {
color: #666666;
font-size: 14px;
margin-right: 8px;
}
.tip {
font-size: 14px;
color: #ff4f4f;
margin-right: 2px;
}
.course-state {
color: #999;
font-size: 14px;
}
}
.ant-table-content {
border: 1px solid #e8e8e8;
tr {
td {
border: none;
}
.course-info{
margin-left:57px;
.course-type{
font-size:11px;
color:#666666;
padding:0px 6px;
line-height: 16px;
border: 1px solid #999999;
margin-right:4px;
border-radius: 2px;
}
.course-name{
color:#666666;
font-size:14px;
margin-right:8px;
.child-table {
.ant-table-content {
border: none;
thead {
display: none;
}
.tip{
font-size:14px;
color:#FF4F4F;
margin-right:2px;
}
.course-state{
color:#999;
font-size:14px;
tbody tr td {
border-bottom: none;
}
}
}
.ant-table-content{
border:1px solid #e8e8e8;
tr{
td{
border:none;
}
.child-table{
.ant-table-content{
border:none;
thead{
display:none;
}
tbody tr td{
border-bottom:none;
}
}
}
}
.odd-row{
background:transparent;
td{
background: #FFF;
}
& + .ant-table-expanded-row{
background:transparent;
td{
background: #FFF;
}
}
&:hover{
& + .ant-table-expanded-row{
background:transparent;
td{
background: #F3f6fa !important;
}
}
}
}
.odd-row {
background: transparent;
td {
background: #fff;
}
& + .ant-table-expanded-row {
background: transparent;
td {
background: #fff;
}
}
&:hover {
& + .ant-table-expanded-row {
background: transparent;
td {
background: #f3f6fa !important;
}
.even-row{
background:transparent;
td{
background: #FAFAFA;
}
& + .ant-table-expanded-row
{
background:transparent
;
td{
background: #FAFAFA;
}
}
&:hover{
& + .ant-table-expanded-row{
background:transparent;
td
{
background: #F3f6fa !important;
}
}
}
}
}
}
.even-row {
background: transparent;
td
{
background: #fafafa
;
}
& + .ant-table-expanded-row {
background: transparent;
td {
background: #fafafa;
}
}
&:hover
{
& + .ant-table-expanded-row {
background: transparent;
td {
background: #f3f6fa !important;
}
}
}
}
}
}
\ No newline at end of file
}
}
src/modules/course-manage/video-course/components/VideoCourseList.jsx
View file @
b427be83
import
React
from
'react'
import
{
Modal
,
message
,
Tooltip
,
Switch
,
Dropdown
}
from
'antd'
import
_
from
'underscore'
import
{
PageControl
}
from
'@/components'
import
{
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
import
{
Route
,
withRouter
}
from
'react-router-dom'
import
ShareLiveModal
from
'@/modules/course-manage/modal/ShareLiveModal'
import
CourseService
from
'@/domains/course-domain/CourseService'
import
RelatedPlanModal
from
'../../modal/RelatedPlanModal'
import
User
from
'@/common/js/user'
import
VideoCourseDetail
from
'../VideoCourseDetail'
import
WatchData
from
'./WatchData'
import
{
XMTable
}
from
'@/components'
import
college
from
'@/common/lottie/college'
import
'./VideoCourseList.less'
import
React
from
'react'
;
import
{
Modal
,
message
,
Tooltip
,
Switch
,
Dropdown
}
from
'antd'
;
import
_
from
'underscore'
;
import
{
PageControl
}
from
'@/components'
;
import
{
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
ShareLiveModal
from
'@/modules/course-manage/modal/ShareLiveModal'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
RelatedPlanModal
from
'../../modal/RelatedPlanModal'
;
import
User
from
'@/common/js/user'
;
import
VideoCourseDetail
from
'../VideoCourseDetail'
;
import
WatchData
from
'./WatchData'
;
import
{
XMTable
}
from
'@/components'
;
import
college
from
'@/common/lottie/college'
;
import
'./VideoCourseList.less'
;
class
VideoCourseList
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
)
super
(
props
)
;
this
.
state
=
{
id
:
''
,
// 视频课ID
studentIds
:
[],
...
...
@@ -24,36 +24,36 @@ class VideoCourseList extends React.Component {
selectPlanList
:
{},
ShelfLoading
:
false
,
// dataSource: [],
}
}
;
}
componentDidMount
()
{
const
videoCourseItem
=
localStorage
.
getItem
(
'videoCourseItem'
)
const
videoCourseItem
=
localStorage
.
getItem
(
'videoCourseItem'
)
;
if
(
videoCourseItem
)
{
const
_videoCourseItem
=
JSON
.
parse
(
videoCourseItem
)
this
.
handleShowShareModal
(
_videoCourseItem
,
true
)
const
_videoCourseItem
=
JSON
.
parse
(
videoCourseItem
)
;
this
.
handleShowShareModal
(
_videoCourseItem
,
true
)
;
}
}
// 跳转课程详情页
handleLinkToCourseDetail
=
(
courseId
)
=>
{
const
{
match
}
=
this
.
props
const
{
match
}
=
this
.
props
;
window
.
RCHistory
.
push
(
`
${
match
.
url
}
/video-course-detail?courseId=
${
courseId
}
`
)
}
window
.
RCHistory
.
push
(
`
${
match
.
url
}
/video-course-detail?courseId=
${
courseId
}
`
)
;
}
;
// 观看数据弹窗
handleShowWatchDataModal
=
(
item
)
=>
{
const
{
match
}
=
this
.
props
const
{
match
}
=
this
.
props
;
window
.
RCHistory
.
push
({
pathname
:
`
${
match
.
url
}
/course-data?courseName=
${
item
.
courseName
}
&courseId=
${
item
.
id
}
`
,
})
}
})
;
}
;
// 请求表头
parseColumns
=
()
=>
{
const
{
type
}
=
this
.
props
const
{
ShelfLoading
}
=
this
.
state
const
{
type
}
=
this
.
props
;
const
{
ShelfLoading
}
=
this
.
state
;
const
columns
=
[
{
title
:
'线上课'
,
...
...
@@ -62,7 +62,7 @@ class VideoCourseList extends React.Component {
width
:
321
,
fixed
:
'left'
,
render
:
(
val
,
record
)
=>
{
const
{
coverUrl
}
=
record
const
{
coverUrl
}
=
record
;
return
(
<
div
className=
'record__item'
>
<
img
className=
'course-cover'
src=
{
coverUrl
||
'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png'
}
alt=
'封面图'
/>
...
...
@@ -77,7 +77,7 @@ class VideoCourseList extends React.Component {
</
Otherwise
>
</
Choose
>
</
div
>
)
)
;
},
},
{
...
...
@@ -97,7 +97,7 @@ class VideoCourseList extends React.Component {
dataIndex
:
'categoryName'
,
width
:
150
,
render
:
(
val
,
record
)
=>
{
return
<
div
className=
'record__item'
>
{
record
.
categorySonName
}
</
div
>
return
<
div
className=
'record__item'
>
{
record
.
categorySonName
}
</
div
>
;
},
},
{
...
...
@@ -108,7 +108,7 @@ class VideoCourseList extends React.Component {
width
:
100
,
align
:
'right'
,
render
:
(
val
,
item
)
=>
{
return
<
div
onClick=
{
()
=>
this
.
handleLinkToCourseDetail
(
item
.
id
)
}
>
{
val
||
1
}
</
div
>
return
<
div
onClick=
{
()
=>
this
.
handleLinkToCourseDetail
(
item
.
id
)
}
>
{
val
||
1
}
</
div
>
;
},
},
{
...
...
@@ -140,10 +140,10 @@ class VideoCourseList extends React.Component {
checked=
{
item
.
shelfState
===
'YES'
}
defaultChecked=
{
item
.
shelfState
}
onClick=
{
(
checked
)
=>
{
this
.
changeShelfState
(
checked
,
item
,
index
)
this
.
changeShelfState
(
checked
,
item
,
index
)
;
}
}
/>
)
)
;
},
},
{
...
...
@@ -157,7 +157,7 @@ class VideoCourseList extends React.Component {
<
div
className=
'watchUserCount'
onClick=
{
()
=>
this
.
handleShowWatchDataModal
(
item
)
}
>
{
val
||
0
}
</
div
>
)
)
;
},
},
{
...
...
@@ -174,7 +174,7 @@ class VideoCourseList extends React.Component {
</
Tooltip
>
)
}
</
div
>
)
)
;
},
},
{
...
...
@@ -184,7 +184,7 @@ class VideoCourseList extends React.Component {
dataIndex
:
'created'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
;
},
},
{
...
...
@@ -194,7 +194,7 @@ class VideoCourseList extends React.Component {
dataIndex
:
'updated'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
return
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
;
},
},
{
...
...
@@ -210,10 +210,10 @@ class VideoCourseList extends React.Component {
<
Tooltip
title=
{
this
.
handlePlanName
(
record
.
relatedPlanList
)
}
placement=
'top'
arrowPointAtCenter
>
{
record
.
relatedPlanList
.
map
((
item
,
index
)
=>
{
return
(
<
span
key=
{
item
.
plan
Id
}
>
<
span
key=
{
item
.
task
Id
}
>
{
item
.
planName
}
{
index
<
record
.
relatedPlanList
.
length
-
1
&&
<
span
>
、
</
span
>
}
</
span
>
)
)
;
})
}
</
Tooltip
>
</
When
>
...
...
@@ -222,7 +222,7 @@ class VideoCourseList extends React.Component {
</
Otherwise
>
</
Choose
>
</
div
>
)
)
;
},
},
{
...
...
@@ -249,17 +249,17 @@ class VideoCourseList extends React.Component {
</
span
>
</
Dropdown
>
</
div
>
)
)
;
},
},
]
]
;
type
!==
'internal'
&&
columns
.
splice
(
5
,
1
)
return
columns
}
type
!==
'internal'
&&
columns
.
splice
(
5
,
1
)
;
return
columns
;
}
;
renderMoreOperate
=
(
item
)
=>
{
const
{
type
}
=
this
.
props
const
{
type
}
=
this
.
props
;
return
(
<
div
className=
'live-course-more-menu'
>
<
If
condition=
{
type
!==
'internal'
}
>
...
...
@@ -269,14 +269,14 @@ class VideoCourseList extends React.Component {
</
If
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<
div
className=
'operate__item'
onClick=
{
()
=>
this
.
handleRelatedModalShow
(
item
)
}
>
关联培训
计划
关联培训
任务
</
div
>
)
}
<
If
condition=
{
type
===
'internal'
}
>
<
div
className=
'operate__item'
onClick=
{
()
=>
{
window
.
RCHistory
.
push
(
`/create-video-course?type=edit&id=${item.id}`
)
window
.
RCHistory
.
push
(
`/create-video-course?type=edit&id=${item.id}`
)
;
}
}
>
编辑
</
div
>
...
...
@@ -285,41 +285,41 @@ class VideoCourseList extends React.Component {
</
div
>
</
If
>
</
div
>
)
}
)
;
}
;
handlePlanName
=
(
planArray
)
=>
{
let
planStr
=
''
let
planStr
=
''
;
planArray
.
forEach
((
item
,
index
)
=>
{
if
(
index
<
planArray
.
length
-
1
)
{
planStr
=
planStr
+
item
.
planName
+
'、'
planStr
=
planStr
+
item
.
planName
+
'、'
;
}
else
{
planStr
=
planStr
+
item
.
planName
planStr
=
planStr
+
item
.
planName
;
}
})
return
planStr
}
})
;
return
planStr
;
}
;
//改变上架状态
changeShelfState
=
(
checked
,
item
,
index
)
=>
{
let
_shelfState
=
checked
?
'YES'
:
'NO'
let
_shelfState
=
checked
?
'YES'
:
'NO'
;
if
(
checked
)
{
_shelfState
=
'YES'
_shelfState
=
'YES'
;
}
else
{
_shelfState
=
'NO'
_shelfState
=
'NO'
;
}
const
params
=
{
courseId
:
item
.
id
,
shelfState
:
_shelfState
,
}
}
;
CourseService
.
changeVideoShelfState
(
params
).
then
(()
=>
{
if
(
_shelfState
===
'YES'
)
{
message
.
success
(
'已开启展示'
)
message
.
success
(
'已开启展示'
)
;
}
else
{
message
.
success
(
'已取消展示'
)
message
.
success
(
'已取消展示'
)
;
}
this
.
props
.
changeShelfState
(
index
,
_shelfState
)
})
}
this
.
props
.
changeShelfState
(
index
,
_shelfState
)
;
})
;
}
;
// 删除线上课
handleDeleteVideoCourse
=
(
scheduleId
)
=>
{
...
...
@@ -334,28 +334,28 @@ class VideoCourseList extends React.Component {
const
param
=
{
courseId
:
scheduleId
,
storeId
:
User
.
getStoreId
(),
}
}
;
CourseService
.
delVideoSchedule
(
param
).
then
(()
=>
{
message
.
success
(
'删除成功'
)
this
.
props
.
onChange
()
})
message
.
success
(
'删除成功'
)
;
this
.
props
.
onChange
()
;
})
;
},
})
}
})
;
}
;
// 显示分享弹窗
handleShowShareModal
=
(
record
,
needStr
=
false
)
=>
{
const
{
type
}
=
this
.
props
const
{
id
,
scheduleVideoUrl
}
=
record
const
htmlUrl
=
`
${
LIVE_SHARE
}
video_detail/
${
id
}
?id=
${
User
.
getStoreId
()}
`
const
longUrl
=
htmlUrl
const
{
coverUrl
,
courseName
}
=
record
const
{
type
}
=
this
.
props
;
const
{
id
,
scheduleVideoUrl
}
=
record
;
const
htmlUrl
=
`
${
LIVE_SHARE
}
video_detail/
${
id
}
?id=
${
User
.
getStoreId
()}
`
;
const
longUrl
=
htmlUrl
;
const
{
coverUrl
,
courseName
}
=
record
;
const
shareData
=
{
longUrl
,
coverUrl
,
scheduleVideoUrl
,
courseName
,
}
}
;
const
shareLiveModal
=
(
<
ShareLiveModal
...
...
@@ -367,82 +367,82 @@ class VideoCourseList extends React.Component {
close=
{
()
=>
{
this
.
setState
({
shareLiveModal
:
null
,
})
localStorage
.
setItem
(
'videoCourseItem'
,
''
)
})
;
localStorage
.
setItem
(
'videoCourseItem'
,
''
)
;
}
}
/>
)
)
;
this
.
setState
({
shareLiveModal
})
}
this
.
setState
({
shareLiveModal
})
;
}
;
handleChangeTable
=
(
pagination
,
filters
,
sorter
)
=>
{
const
{
columnKey
,
order
}
=
sorter
const
{
query
}
=
this
.
props
let
{
order
:
_order
}
=
query
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
this
.
props
;
let
{
order
:
_order
}
=
query
;
// 按创建时间升序排序
if
(
columnKey
===
'created'
&&
order
===
'ascend'
)
{
_order
=
'CREATED_ASC'
_order
=
'CREATED_ASC'
;
}
// 按创建时间降序排序
if
(
columnKey
===
'created'
&&
order
===
'descend'
)
{
_order
=
'CREATED_DESC'
_order
=
'CREATED_DESC'
;
}
// 按更新时间升序排序
if
(
columnKey
===
'updated'
&&
order
===
'ascend'
)
{
_order
=
'UPDATED_ASC'
_order
=
'UPDATED_ASC'
;
}
// 按更新时间降序排序
if
(
columnKey
===
'updated'
&&
order
===
'descend'
)
{
_order
=
'UPDATED_DESC'
_order
=
'UPDATED_DESC'
;
}
const
_query
=
{
...
query
,
orderEnum
:
_order
,
}
this
.
props
.
onChange
(
_query
)
}
}
;
this
.
props
.
onChange
(
_query
)
;
}
;
handleRelatedModalShow
=
(
item
)
=>
{
const
selectPlanList
=
{}
const
selectPlanList
=
{}
;
if
(
item
.
relatedPlanList
)
{
item
.
relatedPlanList
.
map
((
i
tem
,
index
)
=>
{
selectPlanList
[
item
.
planId
]
=
{}
selectPlanList
[
item
.
planId
].
planId
=
item
.
planId
selectPlanList
[
item
.
planId
].
taskBaseVOList
=
[{
taskId
:
item
.
taskId
}]
return
item
})
item
.
relatedPlanList
.
map
((
childI
tem
,
index
)
=>
{
selectPlanList
[
childItem
.
taskId
]
=
{};
selectPlanList
[
childItem
.
taskId
].
taskId
=
childItem
.
taskId
;
selectPlanList
[
childItem
.
taskId
].
taskBaseVOList
=
[{
stageId
:
childItem
.
stageId
}];
return
item
;
})
;
}
this
.
setState
({
RelatedPlanModalVisible
:
true
,
selectCourseId
:
item
.
id
,
selectPlanList
:
selectPlanList
,
})
}
})
;
}
;
closeRelatedPlanModalVisible
=
()
=>
{
this
.
setState
({
RelatedPlanModalVisible
:
false
,
})
}
})
;
}
;
onChangeSelectPlanList
=
(
selectPlanList
)
=>
{
this
.
setState
({
selectPlanList
:
selectPlanList
,
})
}
})
;
}
;
onConfirmSelectPlanList
=
()
=>
{
this
.
setState
(
{
RelatedPlanModalVisible
:
false
,
},
()
=>
{
this
.
props
.
onChange
()
this
.
props
.
onChange
()
;
}
)
}
)
;
}
;
render
()
{
const
{
dataSource
=
[],
totalCount
,
query
,
type
,
match
}
=
this
.
props
const
{
current
,
size
}
=
query
const
{
RelatedPlanModalVisible
,
selectPlanList
,
selectCourseId
}
=
this
.
state
const
{
dataSource
=
[],
totalCount
,
query
,
type
,
match
}
=
this
.
props
;
const
{
current
,
size
}
=
query
;
const
{
RelatedPlanModalVisible
,
selectPlanList
,
selectCourseId
}
=
this
.
state
;
return
(
<
div
className=
{
`video-course-list ${type !== 'internal' ? 'video-course-list-mt' : ''}`
}
>
<
XMTable
...
...
@@ -466,8 +466,8 @@ class VideoCourseList extends React.Component {
pageSize=
{
size
}
total=
{
totalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
query
,
current
:
page
+
1
}
this
.
props
.
onChange
(
_query
)
const
_query
=
{
...
query
,
current
:
page
+
1
}
;
this
.
props
.
onChange
(
_query
)
;
}
}
/>
</
div
>
...
...
@@ -486,8 +486,8 @@ class VideoCourseList extends React.Component {
<
Route
path=
{
`${match.url}/video-course-detail`
}
component=
{
VideoCourseDetail
}
/>
<
Route
path=
{
`${match.url}/course-data`
}
component=
{
WatchData
}
/>
</
div
>
)
)
;
}
}
export
default
withRouter
(
VideoCourseList
)
export
default
withRouter
(
VideoCourseList
)
;
src/modules/home/Home.jsx
View file @
b427be83
import
React
,
{
useEffect
,
useState
}
from
'react'
import
{
Select
,
Tooltip
,
Carousel
,
Popover
}
from
'antd'
import
DataSet
from
'@antv/data-set'
import
{
Chart
as
G2Chart
}
from
'@antv/g2'
import
{
G2
,
Chart
,
Geom
,
Axis
,
Tooltip
as
G2Tooltip
,
Coord
,
Label
,
Legend
,
View
,
Guide
,
Shape
,
Facet
,
Util
}
from
'bizcharts'
import
moment
from
'moment'
import
Service
from
'@/common/js/service'
import
User
from
'@/common/js/user'
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Select
,
Tooltip
,
Carousel
,
Popover
}
from
'antd'
;
import
DataSet
from
'@antv/data-set'
;
import
{
Chart
as
G2Chart
}
from
'@antv/g2'
;
import
{
G2
,
Chart
,
Geom
,
Axis
,
Tooltip
as
G2Tooltip
,
Coord
,
Label
,
Legend
,
View
,
Guide
,
Shape
,
Facet
,
Util
}
from
'bizcharts'
;
import
moment
from
'moment'
;
import
Service
from
'@/common/js/service'
;
import
User
from
'@/common/js/user'
;
import
HomeTip
from
'./HomeTip'
import
'./Home.less'
import
HomeTip
from
'./HomeTip'
;
import
'./Home.less'
;
const
Option
=
Select
.
Option
const
Option
=
Select
.
Option
;
class
Home
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
)
super
(
props
)
;
this
.
state
=
{
scheduleType
:
'LIVE'
,
list
:
[],
...
...
@@ -34,54 +34,54 @@ class Home extends React.Component {
incWeekVisitCustomerNum
:
0
,
courseNum
:
0
,
//课程总数
inCourseNum
:
0
,
//本月新增课程总数
}
this
.
_chart
=
null
}
;
this
.
_chart
=
null
;
}
componentDidMount
()
{
this
.
getPanelInfo
()
this
.
getStudyInfo
()
this
.
getHotCourse
()
this
.
getTrainingInfo
()
this
.
getPanelInfo
()
;
this
.
getStudyInfo
()
;
this
.
getHotCourse
()
;
this
.
getTrainingInfo
()
;
}
getTrainingInfo
()
{
Service
.
Hades
(
'public/hades/planOverview'
,
{
storeId
:
User
.
getStoreId
()
}).
then
((
res
)
=>
{
if
(
res
.
success
)
{
this
.
setState
(
res
.
result
)
this
.
setState
(
res
.
result
)
;
}
})
})
;
}
getHotCourse
()
{
const
{
timeRange
,
scheduleType
}
=
this
.
state
const
{
timeRange
,
scheduleType
}
=
this
.
state
;
const
data
=
{
hotNum
:
5
,
scheduleType
,
storeId
:
User
.
getStoreId
(),
timeRange
,
}
}
;
Service
.
Hades
(
'public/courseCloud/hotCourse'
,
data
).
then
((
res
)
=>
{
if
(
res
.
success
)
{
this
.
setState
({
list
:
res
.
result
,
})
})
;
}
})
})
;
}
getStudyInfo
()
{
const
{
studyTimeRange
}
=
this
.
state
const
{
studyTimeRange
}
=
this
.
state
;
Service
.
Hades
(
'public/hades/studyInfo'
,
{
storeId
:
User
.
getStoreId
(),
timeRange
:
studyTimeRange
}).
then
((
res
)
=>
{
if
(
res
.
success
)
{
const
dataList
=
res
.
result
.
map
((
item
)
=>
({
time
:
moment
(
item
.
dateline
).
format
(
'MM-DD'
),
studyNum
:
item
.
studyNum
,
studyTime
:
Math
.
round
(
item
.
studyTime
/
6
)
/
10
,
}))
this
.
createChart
(
dataList
)
}))
;
this
.
createChart
(
dataList
)
;
}
})
})
;
}
getPanelInfo
()
{
...
...
@@ -106,22 +106,22 @@ class Home extends React.Component {
incWeekVisitCustomerNum
:
res
.
result
.
incWeekVisitCustomerNum
,
courseNum
:
res
.
result
.
videoCourseNum
+
res
.
result
.
liveCourseNum
+
res
.
result
.
pictureCourseNum
+
res
.
result
.
offlineCourseNum
,
inCourseNum
:
res
.
result
.
incLiveCourseNum
+
res
.
result
.
incVideoCourseNum
+
res
.
result
.
incPictureCourseNum
+
res
.
result
.
incOfflineCourseNum
,
})
})
;
}
})
})
;
}
showNumber
(
index
)
{
switch
(
index
)
{
case
0
:
return
'https://image.xiaomaiketang.com/xm/D64QhNn74S.png'
return
'https://image.xiaomaiketang.com/xm/D64QhNn74S.png'
;
case
1
:
return
'https://image.xiaomaiketang.com/xm/Qfib4mnGJT.png'
return
'https://image.xiaomaiketang.com/xm/Qfib4mnGJT.png'
;
case
2
:
return
'https://image.xiaomaiketang.com/xm/8jKXHyrDaG.png'
return
'https://image.xiaomaiketang.com/xm/8jKXHyrDaG.png'
;
default
:
return
'https://image.xiaomaiketang.com/xm/D64QhNn74S.png'
return
'https://image.xiaomaiketang.com/xm/D64QhNn74S.png'
;
}
}
...
...
@@ -132,28 +132,28 @@ class Home extends React.Component {
forceFit
:
true
,
height
:
290
,
padding
:
[
48
,
64
],
})
})
;
}
this
.
_chart
.
clear
()
this
.
_chart
.
clear
()
;
this
.
_chart
.
source
(
data
,
{
studyTime
:
{
formatter
:
(
val
)
=>
{
return
val
return
val
;
},
tickCount
:
5
,
},
time
:
{
formatter
:
(
val
)
=>
{
return
`
${
val
}
`
return
`
${
val
}
`
;
},
},
studyNum
:
{
formatter
:
(
val
)
=>
{
return
val
return
val
;
},
tickCount
:
5
,
},
})
})
;
this
.
_chart
.
axis
(
'time'
,
{
label
:
{
offset
:
20
,
...
...
@@ -168,7 +168,7 @@ class Home extends React.Component {
tickLine
:
{
stroke
:
'#E8E8E8'
,
},
})
})
;
this
.
_chart
.
axis
(
'submitCount'
,
{
label
:
{
textStyle
:
{
...
...
@@ -176,7 +176,7 @@ class Home extends React.Component {
fontSize
:
14
,
},
},
})
})
;
this
.
_chart
.
axis
(
'studyTime'
,
{
label
:
{
textStyle
:
{
...
...
@@ -184,7 +184,7 @@ class Home extends React.Component {
fontSize
:
14
,
},
},
})
})
;
this
.
_chart
.
line
()
.
position
(
'time*studyNum'
)
...
...
@@ -193,8 +193,8 @@ class Home extends React.Component {
return
{
name
:
'学习人数'
,
value
:
studyNum
+
'人'
,
}
})
}
;
})
;
this
.
_chart
.
line
()
.
position
(
'time*studyTime'
)
...
...
@@ -203,10 +203,10 @@ class Home extends React.Component {
return
{
name
:
'人均学习时长'
,
value
:
studyTime
+
'分钟'
,
}
})
}
;
})
;
this
.
_chart
.
legend
(
false
)
this
.
_chart
.
legend
(
false
)
;
this
.
_chart
.
tooltip
({
containerTpl
:
'<div class="g2-tooltip" style="background: #fff !important;">'
+
...
...
@@ -214,9 +214,9 @@ class Home extends React.Component {
'<ul class="g2-tooltip-list"></ul></div>'
,
// tooltip 容器模板
itemTpl
:
'<li data-index={index}><span style="background-color:{color};width:8px;height:8px;border-radius:50%;display:inline-block;margin-right:8px;"></span>{name}<span style="display: inline-block; float: right; margin-left: 30px;">{value}</span></li>'
,
// tooltip 每项记录的默认模板
})
this
.
_chart
.
render
()
}
})
;
this
.
_chart
.
render
()
;
}
;
render
()
{
const
{
...
...
@@ -245,7 +245,7 @@ class Home extends React.Component {
offlineCourseNum
,
weekVisitCustomerNum
,
incWeekVisitCustomerNum
,
}
=
this
.
state
}
=
this
.
state
;
const
data
=
[
{
item
:
'已完成培训'
,
...
...
@@ -255,26 +255,26 @@ class Home extends React.Component {
item
:
'未完成培训'
,
count
:
unfinishedNum
,
},
]
const
{
DataView
}
=
DataSet
const
{
Html
}
=
Guide
const
sum
=
data
[
0
].
count
+
data
[
1
].
count
const
dv
=
new
DataView
()
]
;
const
{
DataView
}
=
DataSet
;
const
{
Html
}
=
Guide
;
const
sum
=
data
[
0
].
count
+
data
[
1
].
count
;
const
dv
=
new
DataView
()
;
sum
&&
dv
.
source
(
data
).
transform
({
type
:
'percent'
,
field
:
'count'
,
dimension
:
'item'
,
as
:
'percent'
,
})
})
;
const
cols
=
{
percent
:
{
formatter
:
(
val
)
=>
{
val
=
val
*
100
+
'%'
return
val
val
=
val
*
100
+
'%'
;
return
val
;
},
},
}
}
;
return
(
<
div
className=
'home-page'
>
<
HomeTip
/>
...
...
@@ -357,7 +357,7 @@ class Home extends React.Component {
<
div
className=
'data-item'
>
<
div
className=
'header'
>
<
img
className=
'header-icon'
src=
'https://image.xiaomaiketang.com/xm/jZf3GNY5tY.png'
alt=
''
/>
<
span
className=
'header-word'
>
培训
计划
总数 (个)
</
span
>
<
span
className=
'header-word'
>
培训
任务
总数 (个)
</
span
>
</
div
>
<
div
className=
'data-number'
>
{
trainingPlanNum
}
</
div
>
<
div
className=
'data-footer'
>
...
...
@@ -416,7 +416,7 @@ class Home extends React.Component {
style=
{
{
width
:
88
}
}
value=
{
timeRange
}
onChange=
{
(
value
)
=>
{
this
.
setState
({
timeRange
:
value
},
()
=>
this
.
getHotCourse
())
this
.
setState
({
timeRange
:
value
},
()
=>
this
.
getHotCourse
())
;
}
}
>
<
Option
value=
'7'
>
近7天
</
Option
>
<
Option
value=
'15'
>
近15天
</
Option
>
...
...
@@ -459,8 +459,8 @@ class Home extends React.Component {
</
div
>
<
div
className=
'study-item'
>
<
div
className=
'study-title'
>
培训
计划
完成情况
<
Tooltip
overlayClassName=
'data-plan-tooltip'
title=
'若某人加入多个培训
计划,则需完成所有已加入的培训计划
后,才视为已完成培训'
>
培训
任务
完成情况
<
Tooltip
overlayClassName=
'data-plan-tooltip'
title=
'若某人加入多个培训
任务,则需完成所有已加入的培训任务
后,才视为已完成培训'
>
<
span
className=
'iconfont icon'
>

</
span
>
</
Tooltip
>
<
span
className=
'tip'
>
(本月)
</
span
>
...
...
@@ -479,7 +479,7 @@ class Home extends React.Component {
<
Axis
name=
'percent'
/>
<
G2Tooltip
showTitle=
{
false
}
itemTpl=
'<li><span style="background-color:
{
color
}
;"
class=
"g2-tooltip-marker"
></
span
>
{
name
}
:
{
value
}
</
li
>
'
itemTpl=
'<li><span style="background-color:
{
color
}
;"
class=
"g2-tooltip-marker"
></
span
>
<
span
style=
"margin-right:16px;"
>
{
percent
}
</
span
><
span
>
{
num
}
</
span
>
</
li
>
'
/
>
<
Guide
>
<
Html
...
...
@@ -492,15 +492,15 @@ class Home extends React.Component {
<
Geom
type=
'intervalStack'
position=
'percent'
color=
{
[
'item'
,
[
'#
FFBB54
'
,
'#2966FF'
]]
}
color=
{
[
'item'
,
[
'#
14CCA7
'
,
'#2966FF'
]]
}
tooltip=
{
[
'item*percent'
,
(
item
,
percent
)
=>
{
percent
=
Math
.
round
(
percent
*
100
)
+
'%'
percent
=
Math
.
round
(
percent
*
100
)
+
'%'
;
return
{
n
ame
:
item
,
value
:
percent
,
}
n
um
:
item
===
'未完成培训'
?
unfinishedNum
+
'人'
:
completeNum
+
'人'
,
percent
:
percent
,
}
;
},
]
}
style=
{
{
...
...
@@ -526,15 +526,15 @@ class Home extends React.Component {
</
Otherwise
>
</
Choose
>
<
div
className=
'circle-tip
un
finished'
>
<
div
className=
'circle-tip finished'
>
<
div
className=
'spot'
></
div
>
<
div
className=
'number'
>
{
unfinishedNum
}
人
</
div
>
<
div
className=
'word'
>
未
完成培训
</
div
>
{
/* <div className='number'>{completeNum}人</div> */
}
<
div
className=
'word'
>
已
完成培训
</
div
>
</
div
>
<
div
className=
'circle-tip finished'
>
<
div
className=
'circle-tip
un
finished'
>
<
div
className=
'spot'
></
div
>
<
div
className=
'number'
>
{
completeNum
}
人
</
div
>
<
div
className=
'word'
>
完成培训
</
div
>
{
/* <div className='number'>{unfinishedNum}人</div> */
}
<
div
className=
'word'
>
未
完成培训
</
div
>
</
div
>
</
div
>
</
div
>
...
...
@@ -554,7 +554,7 @@ class Home extends React.Component {
style=
{
{
width
:
88
}
}
value=
{
studyTimeRange
}
onChange=
{
(
value
)
=>
{
this
.
setState
({
studyTimeRange
:
value
},
()
=>
this
.
getStudyInfo
())
this
.
setState
({
studyTimeRange
:
value
},
()
=>
this
.
getStudyInfo
())
;
}
}
>
<
Option
value=
'7'
>
近7天
</
Option
>
<
Option
value=
'15'
>
近15天
</
Option
>
...
...
@@ -582,8 +582,8 @@ class Home extends React.Component {
</
div
>
</
div
>
</
div
>
)
)
;
}
}
export
default
Home
export
default
Home
;
src/modules/home/Home.less
View file @
b427be83
...
...
@@ -280,18 +280,19 @@
}
.circle-tip {
position: absolute;
left: 70%;
padding-left: 16px;
&.unfinished {
top: 152px;
bottom: 2%;
left: 36%;
.spot {
background: #2966ff;
}
}
&.finished {
top: 232px;
bottom: 2%;
left: 18%;
.spot {
background: #
ffbb54
;
background: #
14cca7
;
}
}
.spot {
...
...
@@ -299,7 +300,7 @@
width: 8px;
height: 8px;
border-radius: 4px;
top:
20
px;
top:
8
px;
left: 0;
}
.number {
...
...
src/modules/knowledge-base/components/KnowledgeBaseList.jsx
View file @
b427be83
...
...
@@ -2,8 +2,8 @@
* @Description:
* @Author: zangsuyun
* @Date: 2021-03-12 14:49:40
* @LastEditors:
yuananting
* @LastEditTime: 2021-0
7-15 14:07:42
* @LastEditors:
wufan
* @LastEditTime: 2021-0
8-15 18:31:16
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
src/modules/knowledge-base/modal/VideoList.jsx
View file @
b427be83
...
...
@@ -3,7 +3,7 @@
* @Author: zangsuyun
* @Date: 2021-03-13 11:48:24
* @LastEditors: wufan
* @LastEditTime: 2021-0
5-30 10:08:09
* @LastEditTime: 2021-0
8-15 18:31:21
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
src/modules/plan-manage/components/BasicInfo.jsx
View file @
b427be83
...
...
@@ -72,11 +72,19 @@ class BasicInfo extends React.Component {
this
.
props
.
onChange
(
'coverId'
,
null
);
},
1000
);
};
handleSelectCover
=
(
file
)
=>
{
this
.
setState
({
visible
:
true
,
imageFile
:
file
,
});
if
(
file
){
this
.
setState
({
visible
:
true
,
imageFile
:
file
,
});
}
else
{
message
.
warning
(
'请选择文件!'
)
}
};
//获取resourceId
getSignature
=
(
blob
,
fileName
)
=>
{
...
...
src/modules/plan-manage/modal/SharePlanModal.jsx
View file @
b427be83
...
...
@@ -6,66 +6,66 @@
* @Description: 大班直播分享弹窗
*/
import
React
from
'react'
import
{
Modal
,
Button
,
message
}
from
'antd'
import
domtoimage
from
'dom-to-image'
import
qrcode
from
'@/libs/qrcode/qrcode.js'
import
User
from
'@/common/js/user'
import
$
from
'jquery'
import
CourseService
from
'@/domains/course-domain/CourseService'
import
React
from
'react'
;
import
{
Modal
,
Button
,
message
}
from
'antd'
;
import
domtoimage
from
'dom-to-image'
;
import
qrcode
from
'@/libs/qrcode/qrcode.js'
;
import
User
from
'@/common/js/user'
;
import
$
from
'jquery'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
'./SharePlanModal.less'
import
'./SharePlanModal.less'
;
const
DEFAULT_COVER
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
const
DEFAULT_COVER
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
;
class
ShareLiveModal
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
)
super
(
props
)
;
this
.
state
=
{
shareUrl
:
''
,
}
}
;
}
componentDidMount
()
{
// 获取短链接
this
.
handleConvertShortUrl
()
this
.
handleConvertShortUrl
()
;
}
handleConvertShortUrl
=
()
=>
{
const
{
longUrl
}
=
this
.
props
.
data
const
{
longUrl
}
=
this
.
props
.
data
;
// 发请求
CourseService
.
getQrcode
({
urls
:
[
longUrl
],
}).
then
((
res
)
=>
{
const
{
result
=
[]
}
=
res
const
{
result
=
[]
}
=
res
;
this
.
setState
(
{
shareUrl
:
result
[
0
].
shortUrl
,
},
()
=>
{
const
qrcodeWrapDom
=
document
.
querySelector
(
'#qrcodeWrap'
)
const
qrcodeWrapDom
=
document
.
querySelector
(
'#qrcodeWrap'
)
;
const
qrcodeNode
=
new
qrcode
({
text
:
this
.
state
.
shareUrl
,
size
:
98
,
})
qrcodeWrapDom
.
appendChild
(
qrcodeNode
)
})
;
qrcodeWrapDom
.
appendChild
(
qrcodeNode
)
;
const
qrcodeWrapDomDownload
=
document
.
querySelector
(
'#qrcodeWrap-dowload'
)
const
qrcodeWrapDomDownload
=
document
.
querySelector
(
'#qrcodeWrap-dowload'
)
;
const
qrcodeNodeDownLoad
=
new
qrcode
({
text
:
this
.
state
.
shareUrl
,
size
:
196
,
})
qrcodeWrapDomDownload
.
appendChild
(
qrcodeNodeDownLoad
)
})
;
qrcodeWrapDomDownload
.
appendChild
(
qrcodeNodeDownLoad
)
;
}
)
})
}
)
;
})
;
}
;
componentWillUnmount
()
{
// 页面销毁之前清空定时器
clearTimeout
(
this
.
timer
)
clearTimeout
(
this
.
timer
)
;
}
// 下载海报
...
...
@@ -77,29 +77,29 @@ class ShareLiveModal extends React.Component {
},
()
=>
{
this
.
setState
({
time
:
new
Date
().
valueOf
()
},
()
=>
{
let
node
=
document
.
getElementById
(
'poster-dowload'
)
let
node
=
document
.
getElementById
(
'poster-dowload'
)
;
domtoimage
.
toPng
(
node
).
then
((
imgData
)
=>
{
const
download
=
document
.
createElement
(
'a'
)
const
{
planName
}
=
this
.
props
.
data
$
(
download
).
attr
(
'href'
,
imgData
).
attr
(
'download'
,
`
${
planName
}
.png`
).
get
(
0
).
click
()
})
})
const
download
=
document
.
createElement
(
'a'
)
;
const
{
planName
}
=
this
.
props
.
data
;
$
(
download
).
attr
(
'href'
,
imgData
).
attr
(
'download'
,
`
${
planName
}
.png`
).
get
(
0
).
click
()
;
})
;
})
;
}
)
}
)
;
}
;
// 复制分享链接
handleCopy
=
()
=>
{
const
textContent
=
document
.
getElementById
(
'shareUrl'
).
innerText
const
textContent
=
document
.
getElementById
(
'shareUrl'
).
innerText
;
window
.
copyText
(
textContent
)
message
.
success
(
'复制成功!'
)
}
window
.
copyText
(
textContent
)
;
message
.
success
(
'复制成功!'
)
;
}
;
render
()
{
const
{
data
}
=
this
.
props
const
{
planName
,
coverUrl
=
DEFAULT_COVER
}
=
data
const
{
shareUrl
,
showImg
,
time
}
=
this
.
state
const
{
data
}
=
this
.
props
;
const
{
planName
,
coverUrl
=
DEFAULT_COVER
}
=
data
;
const
{
shareUrl
,
showImg
,
time
}
=
this
.
state
;
return
(
<
Modal
title=
{
'分享培训计划'
}
...
...
@@ -185,8 +185,8 @@ class ShareLiveModal extends React.Component {
</
div
>
</
div
>
</
Modal
>
)
)
;
}
}
export
default
ShareLiveModal
export
default
ShareLiveModal
;
src/modules/resource-disk/components/FolderList.jsx
View file @
b427be83
...
...
@@ -71,8 +71,10 @@ class FolderList extends React.Component {
handleSelect
=
(
folder
)
=>
{
// 只有文件才有预览功能
if
(
folder
.
folderType
===
'FOLDER'
)
{
console
.
log
(
1
)
this
.
handleSelectFolder
(
folder
)
}
else
{
console
.
log
(
2
)
this
.
handleScanFile
(
folder
)
}
}
...
...
src/modules/root/Header.jsx
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2019-09-10 18:26:03
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
8-11 20:26:53
* @LastEditors:
wufan
* @LastEditTime: 2021-0
9-03 10:32:44
* @Description:
*/
import
React
,
{
useRef
,
useContext
,
useEffect
,
useState
}
from
'react'
;
...
...
@@ -81,6 +81,7 @@ function Header(props) {
setPhone
(
phone
);
setAvatar
(
res
.
result
.
avatar
);
User
.
setAvatar
(
res
.
result
.
avatar
);
User
.
setStoreUserName
(
weChatAccount
);
});
}
...
...
@@ -137,7 +138,7 @@ function Header(props) {
<
Tooltip
title=
{
nickName
}
>
<
div
className=
'name'
>
{
/* <span>{nickName}</span> */
}
<
WWOpenDataCom
type=
"userName"
openid=
{
nickName
}
/>
<
WWOpenDataCom
type=
'userName'
openid=
{
nickName
}
/>
</
div
>
</
Tooltip
>
<
span
className=
'phone'
>
{
phone
}
</
span
>
...
...
@@ -384,7 +385,7 @@ function Header(props) {
/>
<
span
className=
'name'
>
{
/* {nickName} */
}
<
WWOpenDataCom
type=
"userName"
openid=
{
nickName
}
/>
<
WWOpenDataCom
type=
'userName'
openid=
{
nickName
}
/>
</
span
>
</
div
>
</
Dropdown
>
...
...
src/modules/store-manage/EmployeeAddOrEditModal.tsx
View file @
b427be83
/*
* @Author: wufan
* @Date: 2020-11-27 16:21:49
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-08-09 1
1:55:47
* @LastEditors:
yuananting
* @LastEditTime: 2021-08-09 1
9:20:49
* @Description: Description
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
}
from
"react"
;
import
{
Modal
,
Form
,
Button
,
Input
,
InputNumber
,
Radio
,
Row
,
Col
,
message
,
Tooltip
,
}
from
"antd"
;
import
_
,
{
values
}
from
"underscore"
;
import
"./EmployeeAddOrEditModal.less"
;
import
{
CropperModal
}
from
"@/components/"
;
import
StoreService
from
"@/domains/store-domain/storeService"
;
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Modal
,
Form
,
Button
,
Input
,
InputNumber
,
Radio
,
Row
,
Col
,
message
,
Tooltip
}
from
'antd'
;
import
_
,
{
values
}
from
'underscore'
;
import
'./EmployeeAddOrEditModal.less'
;
import
{
CropperModal
}
from
'@/components/'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
import
$
from
"jquery"
;
import
User
from
"@/common/js/user"
;
import
$
from
'jquery'
;
import
User
from
'@/common/js/user'
;
const
RadioGroup
=
Radio
.
Group
;
declare
let
window
:
any
;
...
...
@@ -44,37 +33,28 @@ interface AddEmployeeModalProps {
isWorkWechat
:
boolean
;
}
function
AddEmployeeModal
(
props
:
AddEmployeeModalProps
)
{
const
[
nickName
,
setName
]
=
useState
(
""
);
const
[
phone
,
setPhone
]
=
useState
(
""
);
const
[
role
,
setRole
]
=
useState
(
"CloudOperator"
);
const
[
avatar
,
setAvatar
]
=
useState
(
"https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png"
);
const
[
nickName
,
setName
]
=
useState
(
''
);
const
[
phone
,
setPhone
]
=
useState
(
''
);
const
[
role
,
setRole
]
=
useState
(
'CloudLecturer'
);
const
[
avatar
,
setAvatar
]
=
useState
(
'https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png'
);
const
storeUserId
=
props
.
choosedItem
.
storeUserId
;
const
[
imgUrl
,
setImgUrl
]
=
useState
(
avatar
||
"https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png"
);
const
[
nameErrorMsg
,
setNameErrorMsg
]
=
useState
(
""
);
const
[
nameStatus
,
setNameStatus
]
=
useState
<
""
|
"error"
|
"success"
|
"warning"
|
"validating"
|
undefined
>
();
const
[
phoneErrorMessage
,
setPhoneErrorMessage
]
=
useState
(
""
);
const
[
phoneStatus
,
setPhoneStatus
]
=
useState
<
""
|
"error"
|
"success"
|
"warning"
|
"validating"
|
undefined
>
();
const
[
imgUrl
,
setImgUrl
]
=
useState
(
avatar
||
'https://image.xiaomaiketang.com/xm/rJeQaZxtc7.png'
);
const
[
nameErrorMsg
,
setNameErrorMsg
]
=
useState
(
''
);
const
[
nameStatus
,
setNameStatus
]
=
useState
<
''
|
'error'
|
'success'
|
'warning'
|
'validating'
|
undefined
>
();
const
[
phoneErrorMessage
,
setPhoneErrorMessage
]
=
useState
(
''
);
const
[
phoneStatus
,
setPhoneStatus
]
=
useState
<
''
|
'error'
|
'success'
|
'warning'
|
'validating'
|
undefined
>
();
const
[
cropperModalVisible
,
setCropperModalVisible
]
=
useState
(
false
);
const
[
form
]
=
Form
.
useForm
();
useEffect
(()
=>
{
if
(
props
.
choosedItem
.
nickName
)
{
console
.
log
(
"props.choosedItem"
,
props
.
choosedItem
);
console
.
log
(
'props.choosedItem'
,
props
.
choosedItem
);
setName
(
props
.
choosedItem
.
nickName
);
console
.
log
(
'choosedItem'
,
props
.
choosedItem
);
console
.
log
(
'choosedItem'
,
props
.
choosedItem
);
props
.
choosedItem
.
phone
&&
setPhone
(
props
.
choosedItem
.
phone
);
props
.
choosedItem
.
role
&&
setRole
(
props
.
choosedItem
.
role
[
0
]);
props
.
choosedItem
.
avatar
&&
setAvatar
(
props
.
choosedItem
.
avatar
);
const
_role
=
props
.
choosedItem
.
role
[
0
];
const
_role
=
props
.
choosedItem
.
role
[
0
];
form
.
setFieldsValue
({
nickName
:
props
.
choosedItem
.
nickName
,
role
:
_role
,
...
...
@@ -96,13 +76,13 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
function
_handleUpdateAvatar
(
e
:
any
):
any
{
const
avatar
=
e
.
target
.
files
[
0
];
const
newUrl
=
URL
.
createObjectURL
(
avatar
);
const
$image
=
$
(
"#image"
);
const
$image
=
$
(
'#image'
);
setImgUrl
(
newUrl
);
setCropperModalVisible
(
true
);
}
function
_onUpload
():
any
{
$
(
"#CrpperAvatarPic"
).
trigger
(
"click"
);
$
(
'#CrpperAvatarPic'
).
trigger
(
'click'
);
}
function
changeAvatar
(
img
:
string
):
any
{
...
...
@@ -120,47 +100,47 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
function
handleOk
():
void
{
const
values
=
form
.
getFieldsValue
();
if
(
!
values
.
nickName
.
trim
())
{
setNameErrorMsg
(
"请输入员工昵称"
);
setNameStatus
(
"error"
);
setNameErrorMsg
(
'请输入员工昵称'
);
setNameStatus
(
'error'
);
return
;
}
setNameErrorMsg
(
""
);
setNameStatus
(
""
);
setNameErrorMsg
(
''
);
setNameStatus
(
''
);
if
(
!
String
(
values
.
phone
)
&&
!
props
.
isWorkWechat
)
{
setPhoneErrorMessage
(
"请输入手机号码"
);
setPhoneStatus
(
"error"
);
setPhoneErrorMessage
(
'请输入手机号码'
);
setPhoneStatus
(
'error'
);
return
;
}
setPhoneErrorMessage
(
""
);
setPhoneStatus
(
""
);
setPhoneErrorMessage
(
''
);
setPhoneStatus
(
''
);
if
(
String
(
values
.
phone
).
length
!==
11
&&
!
props
.
isWorkWechat
)
{
setPhoneErrorMessage
(
"请输入11位手机号"
);
setPhoneStatus
(
"error"
);
setPhoneErrorMessage
(
'请输入11位手机号'
);
setPhoneStatus
(
'error'
);
return
;
}
setPhoneErrorMessage
(
""
);
setPhoneStatus
(
""
);
setPhoneErrorMessage
(
''
);
setPhoneStatus
(
''
);
props
.
choosedItem
.
nickName
?
handleEditEmployee
()
:
handleAddEmployee
();
}
function
handleChangeValues
(
name
:
string
,
value
:
any
)
{
switch
(
name
)
{
case
"nickName"
:
case
'nickName'
:
form
.
setFieldsValue
({
nickName
:
value
});
setName
(
value
);
return
;
case
"phone"
:
case
'phone'
:
form
.
setFieldsValue
({
phone
:
value
});
setPhone
(
value
);
setPhoneErrorMessage
(
""
);
setPhoneStatus
(
""
);
setPhoneErrorMessage
(
''
);
setPhoneStatus
(
''
);
return
;
case
"role"
:
case
'role'
:
form
.
setFieldsValue
({
role
:
value
});
setRole
(
value
);
return
;
...
...
@@ -177,9 +157,9 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
roleCodes
:
[
role
],
avatar
,
};
console
.
log
(
"params"
,
params
);
console
.
log
(
'params'
,
params
);
StoreService
.
addEmployee
(
params
).
then
((
res
)
=>
{
message
.
success
(
"保存成功"
);
message
.
success
(
'保存成功'
);
props
.
onClose
();
});
}
...
...
@@ -191,12 +171,12 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
roleCodes
:
[
role
],
avatar
,
storeUserId
:
storeUserId
,
storeId
:
User
.
getStoreId
()
storeId
:
User
.
getStoreId
(),
};
console
.
log
(
"params"
,
params
);
console
.
log
(
'params'
,
params
);
StoreService
.
editEmployee
(
params
).
then
((
res
)
=>
{
message
.
success
(
"编辑成功"
);
message
.
success
(
'编辑成功'
);
props
.
onClose
();
});
}
...
...
@@ -204,119 +184,94 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
return
(
<
Modal
visible=
{
true
}
title=
{
`${props.choosedItem.nickName ?
"编辑员工" : "添加员工"
}`
}
className=
"employee-add-modal"
title=
{
`${props.choosedItem.nickName ?
'编辑员工' : '添加员工'
}`
}
className=
'employee-add-modal'
width=
{
680
}
onCancel=
{
props
.
onClose
}
onOk=
{
handleOk
}
maskClosable=
{
false
}
closeIcon=
{
<
span
className=
"icon iconfont modal-close-icon"
>

</
span
>
}
>
closeIcon=
{
<
span
className=
'icon iconfont modal-close-icon'
>

</
span
>
}
>
<
Row
style=
{
{
height
:
271
}
}
>
<
Col
span=
{
18
}
>
<
Form
{
...
layout
}
form=
{
form
}
name=
"basic"
initialValues=
{
{
nickName
:
nickName
,
phone
:
phone
,
role
:
role
}
}
>
<
Form
{
...
layout
}
form=
{
form
}
name=
'basic'
initialValues=
{
{
nickName
:
nickName
,
phone
:
phone
,
role
:
role
}
}
>
<
Form
.
Item
label=
"员工姓名"
name=
"nickName"
label=
'员工姓名'
name=
'nickName'
// rules={[{ required: true }]}
// validateStatus={nameStatus}
// help={nameErrorMsg || undefined}
style=
{
{
marginBottom
:
0
}
}
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
<
WWOpenDataCom
type=
"userName"
openid=
{
props
.
choosedItem
.
weChatAccount
}
/>
</
div
>
style=
{
{
marginBottom
:
0
}
}
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
<
WWOpenDataCom
type=
'userName'
openid=
{
props
.
choosedItem
.
weChatAccount
}
/>
</
div
>
</
Form
.
Item
>
{
props
.
isWorkWechat
?
(
<
Form
.
Item
label=
"企业微信账号"
name=
"weChatAccount"
>
<
Form
.
Item
label=
'企业微信账号'
name=
'weChatAccount'
>
<
Tooltip
title=
{
props
.
choosedItem
.
weChatAccount
}
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
{
props
.
choosedItem
.
weChatAccount
}
</
div
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
{
props
.
choosedItem
.
weChatAccount
}
</
div
>
</
Tooltip
>
</
Form
.
Item
>
)
:
(
<
Form
.
Item
label=
"手机号码"
name=
"phone"
rules=
{
[{
required
:
true
}]
}
validateStatus=
{
phoneStatus
}
help=
{
phoneErrorMessage
}
>
<
Form
.
Item
label=
'手机号码'
name=
'phone'
rules=
{
[{
required
:
true
}]
}
validateStatus=
{
phoneStatus
}
help=
{
phoneErrorMessage
}
>
<
Input
style=
{
{
width
:
200
}
}
placeholder=
"请输入手机号"
placeholder=
'请输入手机号'
maxLength=
{
11
}
autoComplete=
"off"
autoComplete=
'off'
disabled=
{
!!
props
.
choosedItem
.
nickName
}
onChange=
{
(
e
)
=>
{
if
(
e
.
target
.
value
.
match
(
/^
\d
+$/
))
{
handleChangeValues
(
"phone"
,
e
.
target
.
value
);
handleChangeValues
(
'phone'
,
e
.
target
.
value
);
}
else
{
setPhoneErrorMessage
(
"只能输入数字"
);
setPhoneStatus
(
"error"
);
setPhoneErrorMessage
(
'只能输入数字'
);
setPhoneStatus
(
'error'
);
}
}
}
/>
</
Form
.
Item
>
)
}
<
Form
.
Item
label=
"所在部门"
name=
"weChatAccount"
style=
{
{
marginBottom
:
0
}
}
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
{
props
.
choosedItem
.
depNameList
.
map
((
item
:
any
,
index
:
any
)
=>
{
return
<
span
><
WWOpenDataCom
type=
"departmentName"
openid=
{
item
}
/>
{
index
<
props
.
choosedItem
.
depNameList
.
length
-
1
?
'、'
:
''
}
</
span
>
})
}
</
div
>
<
Form
.
Item
label=
'所在部门'
name=
'weChatAccount'
style=
{
{
marginBottom
:
0
}
}
>
<
div
style=
{
{
whiteSpace
:
'nowrap'
,
textOverflow
:
'ellipsis'
,
overflow
:
'hidden'
,
}
}
>
{
props
.
choosedItem
.
depNameList
.
map
((
item
:
any
,
index
:
any
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
{
index
<
props
.
choosedItem
.
depNameList
.
length
-
1
?
'、'
:
''
}
</
span
>
);
})
}
</
div
>
</
Form
.
Item
>
<
Form
.
Item
label=
"员工角色"
name=
"role"
rules=
{
[{
required
:
false
}]
}
style=
{
{
marginBottom
:
'-2px !important'
}
}
className=
"mt-26"
>
<
Form
.
Item
label=
'员工角色'
name=
'role'
rules=
{
[{
required
:
false
}]
}
style=
{
{
marginBottom
:
'-2px !important'
}
}
className=
'mt-26'
>
<
RadioGroup
onChange=
{
(
e
)
=>
{
handleChangeValues
(
"role"
,
e
.
target
.
value
);
handleChangeValues
(
'role'
,
e
.
target
.
value
);
}
}
className=
"mt5"
>
<
Radio
value=
{
"CloudLecturer"
}
className=
"mt-4"
>
<
span
style=
{
{
color
:
"#333"
}
}
>
普通讲师
</
span
>
<
p
className=
"radio-tip"
>
仅可查看/使用与自己相关的文件和课表,并进行上课
</
p
>
</
Radio
>
<
Radio
value=
{
"CloudManager"
}
>
<
span
style=
{
{
color
:
"#333"
}
}
>
管理员
</
span
>
<
p
className=
"radio-tip"
>
可执行学院中所有的操作
</
p
>
className=
'mt5'
>
<
Radio
value=
{
'CloudLecturer'
}
className=
'mt-4'
>
<
span
style=
{
{
color
:
'#333'
}
}
>
普通讲师
</
span
>
<
p
className=
'radio-tip'
>
仅可查看/使用与自己相关的文件和课表,并进行上课
</
p
>
</
Radio
>
<
Radio
value=
{
"CloudOperator"
}
className=
"mt-4"
>
<
span
style=
{
{
color
:
"#333"
}
}
>
运营师
</
span
>
<
p
className=
"radio-tip"
>
仅可查看/转发培训计划内容,并查看其负责的学员学习进度
</
p
>
<
Radio
value=
{
'CloudManager'
}
>
<
span
style=
{
{
color
:
'#333'
}
}
>
管理员
</
span
>
<
p
className=
'radio-tip'
>
可执行学院中所有的操作
</
p
>
</
Radio
>
</
RadioGroup
>
</
Form
.
Item
>
...
...
@@ -324,10 +279,10 @@ function AddEmployeeModal(props: AddEmployeeModalProps) {
</
Col
>
<
Col
span=
{
6
}
>
<
div
className=
"avatar-box"
>
<
div
className=
"avatar-text"
>
头像
</
div
>
<
div
className=
"avatart-img"
>
<
img
className=
"avatar"
src=
{
avatar
}
></
img
>
<
div
className=
'avatar-box'
>
<
div
className=
'avatar-text'
>
头像
</
div
>
<
div
className=
'avatart-img'
>
<
img
className=
'avatar'
src=
{
avatar
}
></
img
>
</
div
>
</
div
>
</
Col
>
...
...
src/modules/task-center/data-center/Index.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Tabs
}
from
'antd'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
Service
from
'@/common/js/service'
;
import
Breadcrumbs
from
"@/components/Breadcrumbs"
;
import
UserLearningData
from
'./UserLearningData'
;
import
DataInfo
from
'./components/DataInfo'
import
CourseTable
from
'./components/CourseTable'
;
import
DataAnalysic
from
'./components/DataAnalysic'
;
import
ExamTable
from
'./components/ExamTable'
;
import
StudyTable
from
'./components/StudyTable'
;
import
'./index.less'
const
{
TabPane
}
=
Tabs
;
function
DataCenter
(
props
:
any
)
{
const
{
match
}
=
props
;
const
{
params
:
{
taskId
}
}
=
match
;
const
[
info
,
setInfo
]
=
useState
<
any
>
({})
const
[
tabKey
,
setTabKey
]
=
useState
<
any
>
(
''
)
const
tabList
=
[
{
name
:
'课程目录'
,
key
:
'course'
,
compoment
:
CourseTable
,
show
:()
=>
{
return
true
}
},
{
name
:
'学习详情'
,
key
:
'study'
,
compoment
:
StudyTable
,
show
:()
=>
{
return
info
.
courseNum
}
},
{
name
:
'考试详情'
,
key
:
'exam'
,
compoment
:
ExamTable
,
show
:()
=>
{
return
info
.
examNum
}
},
]
useEffect
(()
=>
{
getInfo
()
},
[])
function
getInfo
()
{
Service
.
Hades
(
'/public/hades/getTrainingTaskDetail'
,
{
taskId
}).
then
((
res
:
any
)
=>
{
res
.
result
.
trainingStageList
.
map
((
item
:
any
)
=>
{
item
.
open
=
true
})
res
.
result
.
cover
=
res
.
result
.
courseMediaVOS
.
filter
((
item
:
any
)
=>
item
.
contentType
===
'COVER'
)[
0
]
||
{};
res
.
result
.
intro
=
res
.
result
.
courseMediaVOS
.
filter
((
item
:
any
)
=>
item
.
contentType
===
'INTRO'
)[
0
]
||
{};
setInfo
(
res
.
result
)
})
}
return
<
div
className=
"page train-data-center"
>
<
Breadcrumbs
navList=
"培训任务详情"
goBack=
{
()
=>
{
props
.
history
.
goBack
();
}
}
/>
<
div
className=
"content"
>
<
DataInfo
info=
{
info
}
/>
<
Tabs
defaultActiveKey=
{
'course'
}
onChange=
{
()
=>
{
}
}
>
{
tabList
.
map
((
item
:
any
)
=>
{
return
item
.
show
()
&&
<
TabPane
tab=
{
item
.
name
}
key=
{
item
.
key
}
>
{
<
item
.
compoment
info=
{
info
}
taskId=
{
taskId
}
/>
}
</
TabPane
>
})
}
</
Tabs
>
</
div
>
<
Route
path=
{
`${match.url}/analysic/:id`
}
render=
{
()
=>
{
return
<
DataAnalysic
/>;
}
}
/>
<
Route
path=
{
`${props.match.url}/user-learning-data/:storeCustomerId`
}
render=
{
()
=>
<
UserLearningData
taskId=
{
taskId
}
/>
}
/>
</
div
>
}
export
default
withRouter
(
DataCenter
)
src/modules/task-center/data-center/UserLearningData.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-05 10:55:49
* @LastEditors: wufan
* @LastEditTime: 2021-08-13 17:10:58
* @Description: 个人学习详情
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Tabs
}
from
'antd'
;
import
Breadcrumbs
from
'@/components/Breadcrumbs'
;
import
WholeData
from
'./components/WholeData'
;
import
{
withRouter
}
from
'react-router-dom'
;
import
TestLinkTaskData
from
'./components/TestLinkTaskData'
;
import
CustomerLearnBasicInfo
from
'./components/CustomerLearnBasicInfo'
;
import
User
from
'@/common/js/user'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
import
'./UserLearningData.less'
;
const
{
TabPane
}
=
Tabs
;
function
UserLearningData
(
props
)
{
const
taskId
=
props
.
taskId
;
const
storeCustomerId
=
props
.
match
.
params
.
storeCustomerId
.
replace
(
/
\?
.+/
,
''
);
const
tabList
=
[
{
name
:
'全部'
,
key
:
'whole'
,
compoment
:
WholeData
,
},
{
name
:
'考试'
,
key
:
'exam'
,
compoment
:
TestLinkTaskData
,
// todo
},
];
const
[
detail
,
setDetail
]
=
useState
({});
useEffect
(()
=>
{
getTaskCustomerDetail
();
},
[]);
function
getTaskCustomerDetail
()
{
const
params
=
{
storeCustomerId
,
storeId
:
User
.
getStoreId
(),
taskId
,
};
TaskCenterService
.
getTaskCustomerDetail
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
setDetail
(
result
);
});
}
return
(
<
div
className=
'page user-learning-data'
>
<
Breadcrumbs
navList=
'学员学习数据'
goBack=
{
()
=>
{
props
.
history
.
goBack
();
}
}
/>
<
CustomerLearnBasicInfo
detail=
{
detail
}
/>
<
div
className=
'gap-line'
></
div
>
<
div
className=
'content'
>
<
Tabs
defaultActiveKey=
{
'whole'
}
onChange=
{
()
=>
{}
}
>
{
tabList
.
map
((
item
)
=>
{
return
(
<
TabPane
tab=
{
item
.
name
}
key=
{
item
.
key
}
>
{
<
item
.
compoment
detail=
{
detail
}
taskId=
{
taskId
}
/>
}
</
TabPane
>
);
})
}
</
Tabs
>
</
div
>
</
div
>
);
}
export
default
withRouter
(
UserLearningData
);
src/modules/task-center/data-center/UserLearningData.less
0 → 100644
View file @
b427be83
.user-learning-data {
.header {
padding: 16px 28px;
.train-title {
font-size: 18px;
font-weight: 500;
color: #333333;
line-height: 25px;
position: relative;
&::before {
content: '';
position: absolute;
left: -8px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 10px;
background: #2966ff;
}
&::after {
content: '';
position: absolute;
left: -8px;
top: 75%;
transform: translateY(-50%);
width: 4px;
height: 2px;
background: #0acca4;
}
}
.data-info {
display: flex;
color: #666666;
margin-top: 16px;
margin-bottom: 8px;
.user-name {
margin-right: 32px;
}
.complete-progress {
display: inline-flex;
margin-right: 24px;
}
img {
width: 20px;
height: 20px;
margin-right: 8px;
}
}
}
.gap-line {
height: 10px;
background-color: #f0f2f5;
}
.content {
.ant-tabs-tab {
padding: 20px 20px 14px !important;
// margin-left: 18px;
}
}
}
src/modules/task-center/data-center/components/CourseTable.tsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-16 17:35:15
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 22:06:40
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
'react-router-dom'
;
import
RichText
from
'@/components/RichText'
;
import
ExpiredCourseList
from
'../../train-task/components/ExpiredCourseList'
;
import
ENUM
from
'../../enum'
;
import
'./course.less'
;
function
CourseTable
(
props
:
any
)
{
const
taskId
=
props
.
match
.
params
.
taskId
.
replace
(
/
\?
.+/
,
''
);
const
IndexText
=
[
'一'
,
'二'
,
'三'
,
'四'
,
'五'
,
'六'
,
'七'
,
'八'
,
'九'
,
'十'
];
const
[
list
,
setList
]
=
useState
<
any
[]
>
([]);
useEffect
(()
=>
{
setList
(
props
.
info
.
trainingStageList
||
[]);
},
[
props
.
info
.
trainingStageList
]);
return
(
<
div
className=
'courseTabContent'
>
<
div
className=
'tips'
>
{
`培训目的:`
}
<
RichText
url=
{
props
.
info
?.
intro
?.
mediaUrl
}
/>
</
div
>
<
div
className=
'coursecontent'
>
{
list
?.
map
((
item
:
any
,
index
:
number
)
=>
{
return
(
<
div
className=
'task'
>
<
div
className=
'title'
onClick=
{
()
=>
{
const
_list
=
[...
list
];
_list
[
index
].
open
=
!
_list
[
index
].
open
;
setList
(
_list
);
}
}
>
{
item
.
open
?
<
span
className=
'icon iconfont open'
>

</
span
>
:
<
span
className=
'icon iconfont'
>

</
span
>
}
{
`${IndexText[index]}、 `
}
{
item
.
stageName
}
</
div
>
{
item
.
open
&&
(
<
div
className=
'taskItemList'
>
{
item
.
contentVOList
.
map
((
_item
:
any
,
_index
:
number
)
=>
{
return
(
<
div
className=
{
_index
==
item
.
contentVOList
.
length
-
1
?
'item noBorder'
:
'item'
}
>
<
div
className=
'name'
>
<
img
className=
'type-option-icon'
src=
{
ENUM
.
LearningContentIcon
[
_item
.
courseType
||
_item
.
contentType
]
}
/>
<
span
style=
{
{
marginRight
:
4
}
}
>
{
`${index + 1}.${_index + 1}`
}
</
span
>
{
_item
.
contentName
}
{
_item
.
courseType
==
'LIVE'
&&
<
span
className=
'desc'
>
{
ENUM
.
courseStateShow
[
_item
.
courseState
].
title
}
</
span
>
}
{
_item
.
courseType
==
'VOICE'
&&
<
span
className=
'desc'
>
{
`(共${_item.courseChapterNum}节)`
}
</
span
>
}
</
div
>
</
div
>
);
})
}
</
div
>
)
}
</
div
>
);
})
}
</
div
>
<
div
className=
'expired'
>
<
ExpiredCourseList
taskId=
{
taskId
}
/>
</
div
>
</
div
>
);
}
export
default
withRouter
(
CourseTable
);
src/modules/task-center/data-center/components/CustomerLearnBasicInfo.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-12 18:08:59
* @LastEditors: yuananting
* @LastEditTime: 2021-08-12 18:17:19
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
Progress
,
Space
}
from
'antd'
;
import
ENUM
from
'../../enum'
;
function
CustomerLearnBasicInfo
(
props
)
{
return
(
<
div
className=
'header'
>
<
div
className=
'train-title'
>
{
props
.
detail
.
taskName
}
</
div
>
<
div
className=
'data-info'
>
<
div
className=
'user-name'
>
学员:
{
props
.
detail
.
storeCustomerName
}
</
div
>
<
div
className=
'complete-progress'
>
任务完成率:
<
div
style=
{
{
width
:
120
}
}
>
<
Progress
size=
{
120
}
strokeColor=
'#2966FF'
trailColor=
'#EAEAEA'
percent=
{
props
.
detail
.
learnFinishPercentage
}
size=
'small'
/>
</
div
>
</
div
>
<
Space
size=
{
24
}
>
<
div
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
'COURSE'
]
}
/>
课程:
{
props
.
detail
.
courseFinishNum
||
0
}
/
{
props
.
detail
.
courseAllNum
||
0
}
</
div
>
<
div
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
'EXAM'
]
}
/>
考试:
{
props
.
detail
.
examFinishNum
||
0
}
/
{
props
.
detail
.
examAllNum
||
0
}
</
div
>
</
Space
>
</
div
>
</
div
>
);
}
export
default
CustomerLearnBasicInfo
;
src/modules/task-center/data-center/components/DataAnalysic.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useRef
,
useEffect
,
useContext
}
from
'react'
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
Breadcrumbs
from
"@/components/Breadcrumbs"
;
import
UserData
from
'./UserData'
;
import
ExamData
from
'./ExamData'
import
Service
from
"@/common/js/service"
;
import
{
Tabs
}
from
'antd'
;
import
User
from
"@/common/js/user"
;
import
'./dataAnalysic.less'
const
{
TabPane
}
=
Tabs
;
function
DataAnalysic
(
props
:
any
)
{
const
examDetailInit
:
any
=
{};
const
[
selectKey
,
setSelectKey
]
=
useState
(
'user'
)
const
[
examDetail
,
setExamDetail
]
=
useState
(
examDetailInit
);
const
{
match
}
=
props
;
const
examId
=
match
.
params
.
id
;
useEffect
(()
=>
{
queryExamDetail
();
},
[])
function
queryExamDetail
()
{
Service
.
Hades
(
"public/hades/queryExamDetail"
,
{
examId
:
examId
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
}).
then
((
res
)
=>
{
const
{
result
}
=
res
setExamDetail
(
result
)
})
}
return
<
div
className=
"page dataAnalysic"
>
<
Breadcrumbs
navList=
{
"考试数据"
}
goBack=
{
props
.
history
.
goBack
}
/>
<
div
className=
"box"
>
<
div
className=
"titleBox "
>
考试名称:
{
examDetail
.
examName
}
</
div
>
</
div
>
<
div
className=
"box"
style=
{
{
paddingTop
:
0
}
}
>
<
Tabs
activeKey=
{
selectKey
}
onChange=
{
(
key
:
any
)
=>
{
setSelectKey
(
key
)
}
}
>
<
TabPane
tab=
"考试人员数据"
key=
"user"
>
<
UserData
examDetail
={
examDetail
}
examId=
{
examId
}
/>
</
TabPane
>
<
TabPane
tab=
"题目数据"
key=
"exam"
>
<
ExamData
examDetail
={
examDetail
}
examId=
{
examId
}
></
ExamData
>
</
TabPane
>
</
Tabs
>
</
div
>
</
div
>
}
export
default
withRouter
(
DataAnalysic
);
\ No newline at end of file
src/modules/task-center/data-center/components/DataInfo.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
"react-router-dom"
;
import
{
Progress
}
from
'antd'
;
import
ENUM
from
'../../enum'
import
moment
from
'moment'
const
defaultCover
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
;
function
DataInfo
(
props
:
any
)
{
return
<
div
className=
"infoBox"
>
<
div
className=
"left"
>
<
div
className=
"banner"
>
<
img
src=
{
props
.
info
.
cover
?.
mediaUrl
||
defaultCover
}
alt=
""
/>
</
div
>
<
div
className=
"textBox"
>
<
div
className=
"nameBox"
>
<
div
className=
"name"
>
{
props
.
info
.
taskName
}
</
div
>
<
div
className=
"status"
style=
{
{
color
:
ENUM
.
trainStatus
[
props
.
info
.
taskState
||
'UN_START'
].
color
,
background
:
ENUM
.
trainStatus
[
props
.
info
.
taskState
||
'UN_START'
].
background
}
}
>
{
ENUM
.
trainStatus
[
props
.
info
.
taskState
||
'UN_START'
].
text
}
</
div
>
</
div
>
<
div
className=
"info"
>
<
span
>
{
`创建人: ${props.info.createName} `
}
</
span
>
<
span
style=
{
{
marginLeft
:
24
}
}
>
{
`培训时间:${moment(props.info.startTime).format('YYYY-MM-DD HH:mm')} 至 ${moment(props.info.endTime).format('YYYY-MM-DD HH:mm')}`
}
</
span
>
</
div
>
<
div
className=
"info"
>
<
div
className=
"item"
>
{
`任务数: ${props.info.contentNum}`
}
</
div
>
{
!!
props
.
info
.
courseNum
&&
<
div
className=
"item"
><
span
className=
"icon"
><
img
src=
"https://image.xiaomaiketang.com/xm/6C2GjSpnDp.png"
alt=
""
/></
span
>
{
`课程:${props.info.courseNum}`
}
</
div
>
}
{
/* <div className="item"><span className="icon"><img src="https://image.xiaomaiketang.com/xm/6C2GjSpnDp.png" alt="" /></span>{`作业:4`}</div> */
}
{
!!
props
.
info
.
examNum
&&
<
div
className=
"item"
><
span
className=
"icon"
><
img
src=
"https://image.xiaomaiketang.com/xm/fCDPp2Eenc.png"
alt=
""
/></
span
>
{
`考试:${props.info.examNum}`
}
</
div
>
}
</
div
>
</
div
>
</
div
>
<
div
className=
"right"
>
<
div
className=
"prog"
>
<
Progress
type=
"circle"
width=
{
85
}
percent=
{
parseInt
(
props
.
info
.
finishCustomerNum
/
(
props
.
info
.
cultureCustomerNum
)
*
100
as
any
)
}
strokeWidth=
{
10
}
format=
{
percent
=>
<
div
className=
'wcl'
>
{
`${(parseInt((props.info.finishCustomerNum || 0) /(props.info.cultureCustomerNum || 0)*100 as any))}% `
}
<
div
>
完成率
</
div
>
</
div
>
}
/>
{
/* <div className='wcl'> */
}
{
/* {`${(parseInt(props.info.finishCustomerNum /(props.info.cultureCustomerNum)*100 as any))}% `} */
}
{
/* <div>完成率</div> */
}
{
/* </div> */
}
</
div
>
<
div
className=
"num"
>
<
div
className=
"item"
>
{
`指派人数:${props.info.cultureCustomerNum}`
}
</
div
>
<
div
className=
"item"
>
{
`学习人数:${props.info.learningCustomerNum}`
}
</
div
>
<
div
className=
"item"
>
{
`完成人数:${props.info.finishCustomerNum}`
}
</
div
>
</
div
>
</
div
>
</
div
>
}
export
default
withRouter
(
DataInfo
)
\ No newline at end of file
src/modules/task-center/data-center/components/ExamData.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useRef
,
useEffect
}
from
"react"
;
import
Service
from
"@/common/js/service"
;
import
{
PageControl
}
from
"@/components"
;
import
{
Input
,
Select
,
Tooltip
,
Button
}
from
"antd"
;
import
User
from
"@/common/js/user"
;
import
{
XMTable
}
from
"@/components"
;
import
college
from
"@/common/lottie/college.json"
;
import
"./userData.less"
;
interface
sortType
{
type
:
"ascend"
|
"descend"
|
null
|
undefined
;
}
function
ExamData
(
props
:
any
)
{
const
sortStatus
:
sortType
=
{
type
:
undefined
,
};
const
examDataInit
:
any
=
{};
const
queryInit
:
any
=
{
current
:
1
,
size
:
10
,
order
:
"SORT_ASC"
};
const
[
examData
,
setUserData
]
=
useState
(
examDataInit
);
const
[
list
,
setList
]
=
useState
([]);
const
[
query
,
setQuery
]
=
useState
(
queryInit
);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
field
,
setfield
]
=
useState
(
""
);
const
[
allData
,
setAllData
]
=
useState
(
0
);
const
[
order
,
setOrder
]
=
useState
(
sortStatus
.
type
);
const
questionTypeList
=
{
SINGLE_CHOICE
:
"单选题"
,
MULTI_CHOICE
:
"多选题"
,
JUDGE
:
"判断题"
,
GAP_FILLING
:
"填空题"
,
INDEFINITE_CHOICE
:
"不定项选择题"
,
};
const
userTypeEnum
=
{
WORK_WE_CHAT
:
"企业微信"
,
WE_CHAT
:
"微信"
,
};
const
userExamStateEnum
=
{
EXAM
:
"进行中"
,
LACK_EXAM
:
"缺考"
,
FINISH_EXAM
:
"已考试"
,
};
const
orderEnum
=
{
currentAccuracy
:
{
ascend
:
"ACCURACY_ASC"
,
descend
:
"ACCURACY_DESC"
,
},
};
const
queryRef
=
useRef
({});
useEffect
(()
=>
{
queryExamUserData
();
},
[]);
useEffect
(()
=>
{
queryRef
.
current
=
query
;
queryExamUserDataList
();
},
[
query
]);
function
queryExamUserData
()
{
Service
.
Hades
(
"public/hades/queryExamQuestionData"
,
{
examId
:
props
.
examId
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
setUserData
(
res
.
result
);
});
}
function
queryExamUserDataList
()
{
Service
.
Hades
(
"public/hades/queryExamQuestionDataList"
,
{
...
query
,
examId
:
props
.
examId
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
setList
(
res
.
result
.
records
);
setTotal
(
parseInt
(
res
.
result
.
total
));
if
(
!
allData
)
{
setAllData
(
parseInt
(
res
.
result
.
total
));
}
});
}
const
columns
=
[
{
title
:
"序号"
,
dataIndex
:
"sort"
,
width
:
60
,
render
:
(
text
:
any
,
record
:
any
,
index
:
any
)
=>
<
span
>
{
index
+
1
}
</
span
>,
},
{
title
:
"题目"
,
dataIndex
:
"questionStem"
,
ellipsis
:
true
,
width
:
350
,
render
:
(
val
:
any
)
=>
{
var
handleVal
=
val
;
handleVal
=
handleVal
.
replace
(
/<
(?!
img|input
)
.*
?
>/g
,
""
);
handleVal
=
handleVal
.
replace
(
/<
\s?
input
[^
>
]
*>/gi
,
"_、"
);
handleVal
=
handleVal
.
replace
(
/
\&
nbsp
\;
/gi
,
" "
);
return
(
<
Tooltip
overlayClassName=
"aid-tool-list"
title=
{
<
div
style=
{
{
maxWidth
:
700
,
width
:
"auto"
}
}
>
{
handleVal
}
</
div
>
}
placement=
"topLeft"
overlayStyle=
{
{
maxWidth
:
700
}
}
>
{
handleVal
}
</
Tooltip
>
);
},
},
{
title
:
"题型"
,
dataIndex
:
"questionType"
,
render
:
(
text
:
any
)
=>
<
span
>
{
(
questionTypeList
as
any
)[
text
]
}
</
span
>,
filters
:
Object
.
keys
(
questionTypeList
).
map
((
key
)
=>
{
return
{
text
:
(
questionTypeList
as
any
)[
key
],
value
:
key
,
};
}),
},
{
title
:
"本次正确率"
,
dataIndex
:
"currentAccuracy"
,
sorter
:
true
,
sortOrder
:
field
===
"currentAccuracy"
?
order
:
sortStatus
.
type
,
render
:
(
text
:
any
)
=>
<
span
>
{
parseInt
((
text
*
100
)
as
any
)
}
%
</
span
>,
},
{
title
:
(
<
div
>
历史正确率
{
" "
}
<
Tooltip
overlayClassName=
"tool-list"
title=
"包含本次考试正确率"
placement=
"top"
overlayStyle=
{
{
maxWidth
:
700
}
}
>
{
" "
}
<
span
style=
{
{
color
:
"rgba(191, 191, 191, 1)"
,
fontWeight
:
400
}
}
className=
"icon iconfont"
>

</
span
>
</
Tooltip
>
</
div
>
),
dataIndex
:
"totalAccuracy"
,
render
:
(
text
:
any
)
=>
<
span
>
{
parseInt
((
text
*
100
)
as
any
)
}
%
</
span
>,
},
];
function
onChange
(
pagination
:
any
,
filters
:
any
,
sorter
:
any
,
extra
:
any
)
{
console
.
log
(
filters
,
sorter
);
setfield
(
sorter
.
field
);
setOrder
(
sorter
.
order
);
console
.
log
(
sorter
.
field
,
sorter
.
order
,
(
orderEnum
as
any
)[
sorter
.
field
]);
let
_query
:
any
=
{
...
queryRef
.
current
};
console
.
log
(
filters
.
questionType
);
if
(
filters
.
questionType
)
{
console
.
log
(
233232
);
_query
.
questionType
=
filters
.
questionType
;
_query
.
current
=
1
;
}
else
{
delete
_query
.
questionType
;
}
_query
.
order
=
(
orderEnum
as
any
)[
sorter
.
field
][
sorter
.
order
];
setQuery
(
_query
);
}
function
download
()
{
Service
.
Hades
(
"public/hades/exportExamData"
,
{
// ...query,
examId
:
props
.
examId
,
exportDataType
:
"EXAM_QUESTION_DATA"
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
const
dom
=
(
document
as
any
).
getElementById
(
"load-play-back-excel"
);
dom
.
setAttribute
(
"href"
,
res
.
result
);
dom
.
click
();
});
}
return
(
<
div
className=
"rr"
>
<
a
download
id=
"load-play-back-excel"
style=
{
{
position
:
"absolute"
,
left
:
"-10000px"
}
}
></
a
>
<
div
className=
"dataPanal"
>
{
!!
examData
.
singleChoiceCnt
&&
(
<
div
className=
"item"
>
<
div
className=
"num"
>
{
Math
.
round
((
examData
.
singleChoiceAccuracy
||
0
)
*
100
)
}
%
</
div
>
<
div
className=
"percent"
>
正确率
</
div
>
<
div
className=
"subTitle"
>
<
div
className=
"type"
>
<
span
className=
"icon iconfont"
>

</
span
>
单选题
{
" "
}
<
span
>
(共
{
examData
.
singleChoiceCnt
}
题)
</
span
>
</
div
>
</
div
>
</
div
>
)
}
{
!!
examData
.
multiChoiceCnt
&&
(
<
div
className=
"item"
>
<
div
className=
"num"
>
{
Math
.
round
((
examData
.
multiChoiceAccuracy
||
0
)
*
100
)
}
%
</
div
>
<
div
className=
"percent"
>
正确率
</
div
>
<
div
className=
"subTitle"
>
<
div
className=
"type"
>
<
span
className=
"icon iconfont"
>

</
span
>
多选题
<
span
>
(共
{
examData
.
multiChoiceCnt
}
题)
</
span
>
</
div
>
</
div
>
</
div
>
)
}
{
!!
examData
.
judgeCnt
&&
(
<
div
className=
"item"
>
<
div
className=
"num"
>
{
Math
.
round
((
examData
.
judgeAccuracy
||
0
)
*
100
)
}
%
</
div
>
<
div
className=
"percent"
>
正确率
</
div
>
<
div
className=
"subTitle"
>
<
div
className=
"type"
>
<
span
className=
"icon iconfont"
>

</
span
>
判断题
<
span
>
(共
{
examData
.
judgeCnt
}
题)
</
span
>
</
div
>
</
div
>
</
div
>
)
}
{
!!
examData
.
gapFillingCnt
&&
(
<
div
className=
"item"
>
<
div
className=
"num"
>
{
Math
.
round
((
examData
.
gapFillingAccuracy
||
0
)
*
100
)
}
%
</
div
>
<
div
className=
"percent"
>
正确率
</
div
>
<
div
className=
"subTitle"
>
<
div
className=
"type"
>
<
span
className=
"icon iconfont"
>

</
span
>
填空题
<
span
>
(共
{
examData
.
gapFillingCnt
}
题)
</
span
>
</
div
>
</
div
>
</
div
>
)
}
{
!!
examData
.
indefiniteChoiceCnt
&&
(
<
div
className=
"item"
>
<
div
className=
"num"
>
{
Math
.
round
((
examData
.
indefiniteChoiceAccuracy
||
0
)
*
100
)
}
%
</
div
>
<
div
className=
"percent"
>
正确率
</
div
>
<
div
className=
"subTitle"
>
<
div
className=
"type"
>
<
span
className=
"icon iconfont"
>

</
span
>
不定项选择题
{
" "
}
<
span
>
(共
{
examData
.
indefiniteChoiceCnt
}
题)
</
span
>
</
div
>
</
div
>
</
div
>
)
}
</
div
>
{
!!
allData
&&
(
<
Button
style=
{
{
marginBottom
:
12
,
marginTop
:
12
}
}
onClick=
{
download
}
>
导出
</
Button
>
)
}
<
div
className=
"content"
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
}
}
bordered
size=
"small"
columns=
{
columns
}
dataSource=
{
list
}
onChange=
{
onChange
}
pagination=
{
false
}
></
XMTable
>
{
total
>
0
&&
(
<
PageControl
size=
"small"
current=
{
query
.
current
-
1
}
pageSize=
{
query
.
size
}
total=
{
total
}
toPage=
{
(
page
:
any
)
=>
{
console
.
log
(
page
);
let
_query
:
any
=
{
...
queryRef
.
current
};
_query
.
current
=
page
+
1
;
setQuery
(
_query
);
}
}
/>
)
}
</
div
>
</
div
>
);
}
export
default
ExamData
;
src/modules/task-center/data-center/components/ExamTable.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
Service
from
'@/common/js/service'
;
import
User
from
'@/common/js/user'
;
function
ExamTable
(
props
:
any
)
{
const
{
match
}
=
props
;
console
.
log
(
match
)
const
[
query
,
setQuery
]
=
useState
<
any
>
({
current
:
1
,
size
:
10
,
taskId
:
props
.
taskId
,
source
:
0
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
});
const
[
list
,
setList
]
=
useState
<
any
[]
>
([]);
const
[
total
,
setTotal
]
=
useState
<
any
>
(
0
);
useEffect
(()
=>
{
getList
()
},
[
query
])
function
getList
()
{
Service
.
Hades
(
'public/hades/queryTrainingExamUserData'
,
query
).
then
((
res
:
any
)
=>
{
setList
(
res
.
result
.
records
);
setTotal
(
res
.
result
.
total
);
})
}
const
columns
=
[
{
title
:
'考试名称'
,
key
:
'examName'
,
dataIndex
:
'examName'
,
},
{
title
:
'完成人数'
,
key
:
'finishCnt'
,
dataIndex
:
'finishCnt'
,
},
{
title
:
'平均分'
,
key
:
'averageScore'
,
dataIndex
:
'averageScore'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
val
||
0
}
</
div
>;
},
},
{
title
:
'及格人数'
,
key
:
'passCnt'
,
dataIndex
:
'passCnt'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
val
||
0
}
</
div
>;
},
},
{
title
:
'及格率'
,
key
:
'passPercentage'
,
dataIndex
:
'passPercentage'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
val
}
%
</
div
>;
},
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
(
<
div
className=
'operate-area'
>
<
span
className=
'operate-item'
style=
{
{
color
:
'rgba(41, 102, 255, 1)'
,
cursor
:
'pointer'
}
}
onClick=
{
()
=>
{
props
.
history
.
push
({
pathname
:
`${match.url}/analysic/${record.examId}`
,
});
}
}
>
查看数据
</
span
>
</
div
>
);
},
},
];
return
<
div
className=
"study_Table"
>
<
div
style=
{
{
marginTop
:
12
}
}
>
<
XMTable
renderEmpty=
{
{
type
:
'college'
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
:
any
)
=>
record
.
storeCustomerId
}
dataSource=
{
list
}
columns=
{
columns
}
pagination=
{
false
}
className=
'user-learning-table'
onChange=
{
()
=>
{
}
}
showSorterTooltip=
{
false
}
bordered
/>
{
list
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
query
.
current
-
1
}
pageSize=
{
query
.
size
}
total=
{
total
}
toPage=
{
(
page
:
any
)
=>
{
setQuery
({
...
query
,
current
:
page
+
1
})
}
}
/>
</
div
>
)
}
</
div
>
</
div
>
}
export
default
withRouter
(
ExamTable
)
\ No newline at end of file
src/modules/task-center/data-center/components/LeftStageList.jsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useEffect
}
from
"react"
;
import
"./LeftStageList.less"
;
import
ENUM
from
"../../enum"
;
function
LeftStageList
(
props
)
{
const
{
stageExamList
,
activeExam
,
activeStage
}
=
props
;
const
[
stageList
,
setStageList
]
=
useState
(
stageExamList
||
[]);
// 展开和收起阶段下面的考试
function
handleToggleExpand
(
stageIndex
)
{
let
_taskList
=
[...
stageList
];
_taskList
=
_taskList
.
map
((
item
,
index
)
=>
{
if
(
stageIndex
===
index
)
{
item
.
isShowMoreCourse
=
!
item
.
isShowMoreCourse
;
}
return
item
;
});
setStageList
(
_taskList
||
[]);
}
return
(
<
div
className=
"left-stage-list"
>
{
stageList
.
map
((
item
,
index
)
=>
{
return
(
<
div
key=
{
index
}
className=
"stage-list"
>
<
div
className=
{
`stage-item ${
item.stageId === activeStage.stageId ? "active" : ""
}`
}
onClick=
{
()
=>
handleToggleExpand
(
index
)
}
>
<
div
className=
"icon"
>
{
item
.
isShowMoreCourse
?
(
<
span
className=
"icon iconfont edit-icon"
>

</
span
>
)
:
(
<
span
className=
"icon iconfont edit-icon"
>

</
span
>
)
}
</
div
>
<
div
className=
"stage-name oneLineText"
>
{
ENUM
.
IndexToSort
[
index
+
1
]
}
、
{
item
.
stageName
}
</
div
>
</
div
>
{
!
item
.
isShowMoreCourse
&&
(
<
div
className=
"exam-list"
>
{
item
.
contentVOList
&&
item
.
contentVOList
.
map
((
examItem
,
examIdndex
)
=>
{
return
(
<
div
key=
{
examIdndex
}
className=
{
`exam-item ${
examItem.contentId === activeExam.contentId ? "active" : ""
}`
}
onClick=
{
()
=>
{
props
.
changeActiveExam
(
examItem
,
item
)
}
}
>
<
div
className=
"exam-name"
>
{
item
.
sequence
}
.
{
examItem
.
sequence
}{
' '
}{
examItem
.
contentName
}
</
div
>
</
div
>
);
})
}
</
div
>
)
}
</
div
>
);
})
}
</
div
>
);
}
export
default
LeftStageList
;
src/modules/task-center/data-center/components/LeftStageList.less
0 → 100644
View file @
b427be83
.left-stage-list {
width: 229px;
.stage-list {
.stage-item {
display: flex;
width: 229px;
height: 44px;
background: rgba(255, 255, 255, 0.06);
color: #666;
font-size: 14px;
color: #666;
line-height: 44px;
margin-right: 8px;
cursor: pointer;
.iconfont {
line-height: 15px;
font-size: 10px;
margin: 0 8px;
display: inline-block;
color: #666;
}
&.active {
background: rgba(41, 102, 255, 0.06);
color: #2966ff;
}
}
.exam-list {
.exam-item {
width: 229px;
height: 44px;
background: rgba(255, 255, 255, 0.06);
width: 100%;
font-size: 14px;
color: #666666;
line-height: 44px;
padding-left: 48px;
cursor: pointer;
.exam-name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
&.active {
background-color: RGBA(243, 246, 250, 1);
}
}
}
}
}
src/modules/task-center/data-center/components/StudyTable.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useEffect
,
useRef
,
useState
}
from
'react'
;
import
{
Route
,
withRouter
}
from
"react-router-dom"
;
import
{
Row
,
Input
,
Select
,
Tooltip
,
Col
}
from
'antd'
;
import
RangePicker
from
'@/modules/common/DateRangePicker'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
Service
from
'@/common/js/service'
;
import
ENUM
from
'../../enum'
;
import
User
from
'@/common/js/user'
;
import
moment
from
'moment'
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
declare
var
formatDate
:
any
;
function
StudyTable
(
props
:
any
)
{
console
.
log
(
props
,
'rtyjukl'
)
const
[
query
,
setQuery
]
=
useState
<
any
>
({
size
:
10
,
taskId
:
props
.
taskId
,
source
:
0
,
storeId
:
User
.
getStoreId
(),
storeUserId
:
User
.
getStoreUserId
(),
userId
:
User
.
getStoreUserId
(),
});
const
[
list
,
setList
]
=
useState
<
any
[]
>
([]);
const
[
total
,
setTotal
]
=
useState
<
any
>
(
0
);
const
[
name
,
setName
]
=
useState
<
any
>
(
''
);
const
[
current
,
setCurrent
]
=
useState
<
any
>
(
1
);
const
[
orderFiled
,
setOrderFiled
]
=
useState
<
any
>
(
null
);
const
[
sort
,
setSort
]
=
useState
<
any
>
(
null
);
const
[
sortedList
,
setSortedList
]
=
useState
<
any
[]
>
([]);
const
timer
=
useRef
<
any
>
(
null
);
const
sortNameMap
:
any
=
{
learnPercentage
:
'LEARN_NUM'
,
latelyLearnTime
:
'LATE_LEARN_TIME'
,
startLearnTime
:
'START_LEARN_TIME'
,
}
useEffect
(()
=>
{
getList
()
},
[
query
])
useEffect
(()
=>
{
console
.
log
(
sort
,
orderFiled
)
if
(
sort
&&
orderFiled
)
{
const
_list
=
[...
list
];
_list
.
sort
((
pre
:
any
,
next
:
any
)
=>
{
if
(
sort
===
'ascend'
)
{
return
(
pre
[
orderFiled
]
||
0
)
-
(
next
[
orderFiled
]
||
0
)
}
else
{
return
(
next
[
orderFiled
]
||
0
)
-
(
pre
[
orderFiled
]
||
0
)
}
})
setSortedList
(
_list
)
}
else
{
setSortedList
(
list
)
}
},
[
list
,
sort
,
orderFiled
])
function
getList
()
{
Service
.
Hades
(
'public/hades/getTaskCustomerRecordPage'
,
query
).
then
((
res
:
any
)
=>
{
res
.
result
.
map
((
item
:
any
)
=>
{
item
.
department
=
item
.
departmentNameList
?.
map
((
_item
:
any
)
=>
{
if
(
_item
==
'1000'
)
{
return
'微信'
}
else
{
return
<
WWOpenDataCom
type=
"departmentName"
openid=
{
_item
}
/>
}
})
})
setList
(
res
.
result
)
setTotal
(
res
.
result
.
length
)
})
}
const
columns
=
[
{
title
:
'学员'
,
key
:
'storeCustomerName'
,
dataIndex
:
'storeCustomerName'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
val
}
<
span
className=
"tag"
style=
{
{
color
:
record
.
sourceEnum
===
'WORK_WE_CHAT'
?
'#2966FF'
:
'#1DCC65'
}
}
>
{
record
.
sourceEnum
===
'WORK_WE_CHAT'
?
'@企业微信'
:
'@微信'
}
</
span
>
</
div
>;
},
},
{
title
:
'部门'
,
key
:
'departmentNameList'
,
dataIndex
:
'departmentNameList'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
record
.
department
?.
map
((
item
:
any
,
index
:
number
)
=>
{
if
((
index
+
1
)
==
record
.
department
.
length
)
{
return
item
}
else
{
return
[
item
,
';'
]
}
})
}
</
div
>
},
},
{
title
:
'岗位'
,
key
:
'postNameList'
,
dataIndex
:
'postNameList'
,
},
{
title
:
'学习状态'
,
key
:
'learnState'
,
dataIndex
:
'learnState'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
ENUM
.
learnState
[
val
].
text
}
</
div
>;
},
},
{
title
:
<
div
>
学习进度
<
Tooltip
title=
{
'已完成任务数/任务总数'
}
>
<
span
style=
{
{
color
:
"rgba(191, 191, 191, 1)"
,
fontWeight
:
400
}
}
className=
"iconfont"
>

</
span
>
</
Tooltip
></
div
>,
key
:
'learnPercentage'
,
sorter
:
true
,
dataIndex
:
'learnPercentage'
,
sortOrder
:
(
orderFiled
==
'learnPercentage'
)
?
sort
:
null
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
`
${
val
}
%`
;
},
},
{
title
:
'最近学习时间'
,
key
:
'latelyLearnTime'
,
dataIndex
:
'latelyLearnTime'
,
sorter
:
true
,
width
:
240
,
sortOrder
:
(
orderFiled
==
'latelyLearnTime'
)
?
sort
:
null
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
`
${
formatDate
(
'YYYY-MM-DD H:i'
,
parseInt
(
record
.
latelyLearnTime
))}
`
;
},
},
{
title
:
'开始学习时间'
,
key
:
'startLearnTime'
,
dataIndex
:
'startLearnTime'
,
width
:
240
,
sorter
:
true
,
field
:
'yuiooo'
,
sortOrder
:
(
orderFiled
==
'startLearnTime'
)
?
sort
:
null
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
<
div
>
{
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
div
>;
},
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
(
<
div
className=
'operate-area'
>
<
span
className=
'operate-item'
style=
{
{
color
:
'rgba(41, 102, 255, 1)'
,
cursor
:
'pointer'
}
}
onClick=
{
()
=>
{
props
.
history
.
push
(
`${props.match.url}/user-learning-data/${record.storeCustomerId}`
);
}
}
>
查看数据
</
span
>
</
div
>
);
},
},
];
function
onChange
(
pagination
:
any
,
filters
:
any
,
sorter
:
any
,
extra
:
any
)
{
console
.
log
(
sorter
)
setOrderFiled
(
sorter
.
field
||
null
)
setSort
(
sorter
.
order
)
setCurrent
(
1
)
}
return
<
div
className=
"study_Table"
>
<
div
className=
"filter"
>
<
Row
>
<
Col
span=
{
7
}
>
<
div
className=
'xm_search_item'
>
<
span
className=
'label'
>
学员:
</
span
>
<
div
className=
"search"
>
<
Search
value=
{
name
}
placeholder=
'搜索学员名称'
onChange=
{
(
e
)
=>
{
setName
(
e
.
target
.
value
);
clearTimeout
(
timer
.
current
)
var
name
=
e
.
target
.
value
timer
.
current
=
setTimeout
(()
=>
{
setQuery
({
...
query
,
customerName
:
name
})
setCurrent
(
1
)
},
500
)
}
}
onSearch=
{
()
=>
{
}
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
/>
</
div
>
</
div
>
</
Col
>
<
Col
span=
{
7
}
>
<
div
className=
'xm_search_item'
>
<
span
className=
'label '
>
学习状态:
</
span
>
<
div
className=
"search"
>
<
Select
style=
{
{
width
:
'100%'
}
}
placeholder=
'请选择当前状态'
allowClear=
{
true
}
value=
{
query
.
learnState
}
onChange=
{
(
value
)
=>
{
setQuery
({
...
query
,
learnState
:
value
})
setCurrent
(
1
)
}
}
suffixIcon=
{
<
span
className=
'icon iconfont'
style=
{
{
fontSize
:
'12px'
,
color
:
'#BFBFBF'
}
}
>

</
span
>
}
>
{
Object
.
keys
(
ENUM
.
learnState
).
map
((
key
:
any
)
=>
{
return
<
Option
value=
{
key
}
>
{
ENUM
.
learnState
[
key
].
text
}
</
Option
>
})
}
</
Select
>
</
div
>
</
div
>
</
Col
>
<
Col
span=
{
7
}
>
<
div
className=
'xm_search_item'
>
<
span
className=
'label'
>
最近学习日期:
</
span
>
<
div
className=
"search"
>
<
RangePicker
style=
{
{
width
:
'100%'
}
}
id=
'course_date_picker'
allowClear=
{
false
}
value=
{
query
.
startTime
?
[
moment
(
query
.
startTime
),
moment
(
query
.
endTime
)]
:
null
}
format=
{
'YYYY-MM-DD'
}
onChange=
{
(
dates
:
any
)
=>
{
setQuery
({
...
query
,
startTime
:
dates
[
0
]?.
startOf
(
'day'
).
valueOf
(),
endTime
:
dates
[
0
]?.
endOf
(
'day'
).
valueOf
(),
})
setCurrent
(
1
)
}
}
/>
</
div
>
</
div
>
</
Col
>
<
Col
offset=
{
2
}
span=
{
1
}
>
<
Tooltip
title=
'清空筛选'
>
<
span
className=
'resetBtn iconfont icon'
onClick=
{
()
=>
{
setName
(
''
);
setQuery
({
size
:
10
,
taskId
:
props
.
taskId
,
source
:
0
,
storeId
:
User
.
getStoreId
(),
storeUserId
:
User
.
getStoreUserId
(),
userId
:
User
.
getStoreUserId
(),
})
setCurrent
(
1
)
setSort
(
''
)
}
}
>

{
' '
}
</
span
>
</
Tooltip
>
</
Col
>
</
Row
>
</
div
>
<
div
style=
{
{
marginTop
:
12
}
}
>
<
XMTable
renderEmpty=
{
{
type
:
'college'
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
:
any
,
index
:
any
)
=>
record
.
storeCustomerId
+
'_'
+
index
}
dataSource=
{
sortedList
.
slice
((
current
-
1
)
*
query
.
size
,
current
*
query
.
size
)
}
columns=
{
columns
}
pagination=
{
false
}
className=
'user-learning-table'
onChange=
{
onChange
}
showSorterTooltip=
{
false
}
bordered
/>
{
list
&&
list
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
current
-
1
}
pageSize=
{
query
.
size
}
total=
{
total
}
toPage=
{
(
page
:
any
)
=>
{
setCurrent
(
page
+
1
)
}
}
/>
</
div
>
)
}
</
div
>
</
div
>
}
export
default
withRouter
(
StudyTable
)
\ No newline at end of file
src/modules/task-center/data-center/components/TestLinkTaskData.jsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useEffect
}
from
"react"
;
import
"./TestLinkTaskData.less"
;
import
LeftStageList
from
"./LeftStageList"
;
import
TestDetailPage
from
"@/modules/teach-tool/examination-manager/TestDetailPage"
;
import
{
Route
,
withRouter
}
from
"react-router-dom"
;
import
Service
from
"@/common/js/service"
;
import
LottieIcon
from
"@/components/LottieIcon"
;
import
User
from
'@/common/js/user'
;
function
TestLinkTaskData
(
props
)
{
const
[
stageExamList
,
setStageExamList
]
=
useState
([]);
const
[
activeExam
,
setActiveExam
]
=
useState
({});
const
[
activeStage
,
setActiveStage
]
=
useState
({});
const
[
isShow
,
setIsShow
]
=
useState
(
true
);
const
{
taskId
,
detail
:
{
storeCustomerId
}}
=
props
;
useEffect
(()
=>
{
getTrainingTaskDetail
();
},
[]);
function
getTrainingTaskDetail
()
{
Service
.
Hades
(
"public/hades/getTaskCustomerDetail"
,
{
taskId
:
taskId
,
storeId
:
User
.
getStoreId
(),
storeCustomerId
:
storeCustomerId
,
}).
then
((
res
)
=>
{
const
data
=
{
...
res
.
result
};
const
{
stageExamCustomerVOList
=
[]
}
=
data
;
if
(
!!
stageExamCustomerVOList
.
length
)
{
setStageExamList
(
stageExamCustomerVOList
);
setActiveStage
(
stageExamCustomerVOList
[
0
]);
setActiveExam
(
stageExamCustomerVOList
[
0
].
contentVOList
[
0
]);
const
{
contentId
,
paperId
}
=
stageExamCustomerVOList
[
0
].
contentVOList
[
0
];
const
{
match
}
=
props
;
const
path
=
`
${
match
.
url
}
/test-detail/
${
contentId
}
?paperId=
${
paperId
}
1&userId=
${
storeCustomerId
}
&fromTrainingTask=true`
;
window
.
RCHistory
.
replace
(
path
);
}
});
}
function
changeActiveExam
(
_activeExam
,
_activeStage
)
{
console
.
log
(
"_activeExam"
,
_activeExam
);
setActiveExam
(
_activeExam
);
setActiveStage
(
_activeStage
);
const
{
contentId
,
paperId
}
=
_activeExam
;
const
{
match
}
=
props
;
const
path
=
`
${
match
.
url
}
/test-detail/
${
contentId
}
?paperId=
${
paperId
}
&userId=
${
111
}
`
;
window
.
RCHistory
.
replace
(
path
);
}
function
toggleShowBar
(
diretion
)
{
if
(
diretion
===
"left"
)
{
setIsShow
(
false
);
}
else
{
setIsShow
(
true
);
}
}
return
(
<
div
>
{
stageExamList
.
length
?
(
<
div
className=
{
`test-link-task-data ${!isShow ? 'hidden':''}`
}
>
<
div
className=
{
`left-stage-list-box ${!isShow ? 'hidden':''}`
}
>
{
isShow
?
(
<
div
className=
"left-bar"
onClick=
{
()
=>
{
toggleShowBar
(
"left"
);
}
}
></
div
>
)
:
(
<
div
className=
"right-bar"
onClick=
{
()
=>
{
toggleShowBar
(
"right"
);
}
}
></
div
>
)
}
<
LeftStageList
stageExamList=
{
stageExamList
}
activeExam=
{
activeExam
}
changeActiveExam=
{
changeActiveExam
}
activeStage=
{
activeStage
}
/>
</
div
>
<
div
className=
{
`right-exam-data-box ${!isShow ? 'hidden':''}`
}
>
{
/* 未考过的考试显示暂无考试数据,否则请求接口会报错 */
}
{
activeExam
.
learnFinishPercentage
===
0
?
<
LottieIcon
title=
{
<
span
className=
"desc"
>
暂无考试数据
</
span
>
}
type=
"college"
size=
{
150
}
/>
:
<
Route
path=
{
`${props.match.url}/test-detail/:testId`
}
component=
{
TestDetailPage
}
/>
}
</
div
>
</
div
>
)
:
(
<
LottieIcon
title=
{
<
span
className=
"desc"
>
暂无考试数据
</
span
>
}
type=
"college"
size=
{
150
}
/>
)
}
</
div
>
);
}
export
default
withRouter
(
TestLinkTaskData
);
src/modules/task-center/data-center/components/TestLinkTaskData.less
0 → 100644
View file @
b427be83
.test-link-task-data {
position: relative;
height: calc(100vh - 300px);
border-right: 1px solid #cccccc;
display: flex;
.left-stage-list-box {
border-right: 1px solid #cccccc;
width: 245px;
height: 100%;
overflow-y: auto;
position: relative;
overflow-x: hidden;
&.hidden {
border-left: 1px solid #cccccc;
border-right: none;
width: 15px;
.left-stage-list {
display: none;
}
}
.left-bar {
width: 8px;
height: 68px;
background: #d6d6d6;
border-radius: 12px 0px 0px 12px;
position: absolute;
right: 0;
top: 50%;
&::before {
content: "";
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
width: 0;
height: 0;
transform: rotate(45deg);
background-color: #fff;
box-shadow: 0 0 6px 0 rgba(0, 0, 0, 0.2);
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #fff;
}
&:hover {
width: 12px;
height: 68px;
background: #666666;
border-radius: 12px 0px 0px 12px;
}
}
.right-bar {
width: 8px;
height: 68px;
background: #d6d6d6;
border-radius: 0px 12px 12px 0px;
position: absolute;
left: 0;
top: 50%;
&::before {
content: "";
left: -190%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
width: 0;
height: 0;
transform: rotate(315deg);
background-color: #fff;
box-shadow: 0 0 6px 0 rgb(0 0 0 / 20%);
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #fff;
}
&:hover {
width: 12px;
height: 68px;
background: #666666;
border-radius: 0px 12px 12px 0px;
&::before {
content: "";
left: -120%;
top: 50%;
transform: translate(-50%, -50%);
position: absolute;
width: 0;
height: 0;
transform: rotate(315deg);
background-color: #fff;
box-shadow: 0 0 6px 0 rgb(0 0 0 / 20%);
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #fff;
}
}
}
}
.right-exam-data-box {
width: calc(100vw - 450px);
height: 100%;
overflow-y: auto;
margin-top: -16px;
overflow-x: hidden;
@media screen and (max-width: 1400px) {
.lottie-icon {
text-align: center;
margin-top: 153px;
margin-bottom: 50px;
}
}
&.hidden {
width: calc(100vw - 200px);
}
}
}
src/modules/task-center/data-center/components/UserData.tsx
0 → 100644
View file @
b427be83
import
React
,
{
useState
,
useRef
,
useEffect
}
from
"react"
;
import
Service
from
"@/common/js/service"
;
import
{
PageControl
}
from
"@/components"
;
import
{
Input
,
Select
,
Tooltip
,
Table
,
Button
}
from
"antd"
;
import
{
ColumnsType
}
from
"antd/es/table"
;
import
User
from
"@/common/js/user"
;
import
moment
from
"moment"
;
import
{
XMTable
}
from
"@/components"
;
import
college
from
"@/common/lottie/college.json"
;
import
"./userData.less"
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
declare
var
window
:
any
;
interface
sortType
{
type
:
"ascend"
|
"descend"
|
null
|
undefined
;
}
interface
User
{
key
:
number
;
name
:
string
;
}
function
DataAnalysic
(
props
:
any
)
{
const
sortStatus
:
sortType
=
{
type
:
undefined
,
};
const
useDataInit
:
any
=
{};
const
queryInit
:
any
=
{
current
:
1
,
size
:
10
};
const
[
useData
,
setUserData
]
=
useState
(
useDataInit
);
const
[
list
,
setList
]
=
useState
([]);
const
[
query
,
setQuery
]
=
useState
(
queryInit
);
const
[
total
,
setTotal
]
=
useState
(
0
);
const
[
field
,
setfield
]
=
useState
(
""
);
const
[
allData
,
setAllData
]
=
useState
(
0
);
const
[
order
,
setOrder
]
=
useState
(
sortStatus
.
type
);
const
userTypeEnum
=
{
WORK_WE_CHAT
:
"企业微信"
,
WE_CHAT
:
"微信"
,
};
const
userExamStateEnum
=
{
EXAM
:
"进行中"
,
LACK_EXAM
:
"缺考"
,
FINISH_EXAM
:
"已考试"
,
};
const
ExamPassColorEnum
=
{
EXAM_FAIL
:
"rgba(255, 79, 79, 1)"
,
EXAM_PASS
:
"rgba(59, 189, 170, 1)"
,
};
const
ExamPassEnum
=
{
EXAM_FAIL
:
"不及格"
,
EXAM_PASS
:
"及格"
,
};
const
userExamStateColorEnum
=
{
EXAM
:
"rgba(35, 143, 255, 1)"
,
LACK_EXAM
:
"rgba(204, 204, 204, 1)"
,
FINISH_EXAM
:
"rgba(47, 200, 60, 1)"
,
};
const
orderEnum
=
{
score
:
{
ascend
:
"EXAM_SCORE_ASC"
,
descend
:
"EXAM_SCORE_DESC"
,
},
userDuration
:
{
ascend
:
"USER_DURATION_ASC"
,
descend
:
"USER_DURATION_DESC"
,
},
};
const
queryRef
=
useRef
({});
useEffect
(()
=>
{
queryExamUserData
();
},
[]);
useEffect
(()
=>
{
queryRef
.
current
=
query
;
queryExamUserDataList
();
},
[
query
]);
function
queryExamUserData
()
{
Service
.
Hades
(
"public/hades/queryExamUserData"
,
{
examId
:
props
.
examId
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
setUserData
(
res
.
result
);
});
}
function
queryExamUserDataList
()
{
Service
.
Hades
(
"public/hades/queryExamUserDataList"
,
{
...
query
,
examId
:
props
.
examId
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
setList
(
res
.
result
.
records
);
setTotal
(
parseInt
(
res
.
result
.
total
));
if
(
!
allData
)
{
setAllData
(
parseInt
(
res
.
result
.
total
));
}
});
}
const
columns
:
ColumnsType
<
User
>
=
[
{
title
:
"学员"
,
dataIndex
:
"userName"
,
render
:
(
text
:
any
,
record
:
any
)
=>
(
<
span
>
{
text
}
<
span
style=
{
{
color
:
record
.
userSource
===
"WORK_WE_CHAT"
?
"rgba(255, 157, 20, 1)"
:
"rgba(29, 204, 101, 1)"
,
}
}
>
@
{
(
userTypeEnum
as
any
)[
record
.
userSource
]
}
</
span
>
</
span
>
),
},
{
title
:
"手机号"
,
dataIndex
:
"phone"
,
},
{
title
:
"考试状态"
,
dataIndex
:
"userExamState"
,
render
:
(
text
:
any
)
=>
(
<
span
>
{
" "
}
<
span
className=
"exstatus"
style=
{
{
background
:
(
userExamStateColorEnum
as
any
)[
text
]
}
}
></
span
>
{
" "
}
{
(
userExamStateEnum
as
any
)[
text
]
}
</
span
>
),
},
{
title
:
"考试成绩"
,
dataIndex
:
"score"
,
sorter
:
true
,
sortOrder
:
field
===
"score"
?
order
:
sortStatus
.
type
,
render
:
(
text
:
any
,
record
:
any
)
=>
(
<
span
>
{
" "
}
{
text
}{
" "
}
<
span
style=
{
{
border
:
`1px solid ${
(ExamPassColorEnum as any)[record.examPass]
}`
,
fontSize
:
12
,
color
:
(
ExamPassColorEnum
as
any
)[
record
.
examPass
],
display
:
"inline-block"
,
padding
:
"0px 2px"
,
}
}
>
{
(
ExamPassEnum
as
any
)[
record
.
examPass
]
}
</
span
>
</
span
>
),
},
{
title
:
"进入考试时间"
,
dataIndex
:
"examStartTime"
,
render
:
(
text
:
any
)
=>
(
<
span
>
{
moment
(
text
).
format
(
"YYYY-MM-DD HH:mm"
)
}
</
span
>
),
},
{
title
:
"考试用时"
,
dataIndex
:
"userDuration"
,
sorter
:
true
,
sortOrder
:
field
===
"userDuration"
?
order
:
sortStatus
.
type
,
render
:
(
text
:
any
,
record
:
any
)
=>
(
<
span
>
{
record
.
userExamState
===
"FINISH_EXAM"
?
window
.
formatHourTime
(
text
)
:
"-"
}{
" "
}
</
span
>
),
},
//TODO:
{
title
:
"操作"
,
key
:
""
,
dataIndex
:
"edit"
,
render
:
(
value
:
any
,
record
:
any
)
=>
{
return
(
<
Choose
>
<
When
condition=
{
record
.
userExamState
===
"FINISH_EXAM"
}
>
<
div
className=
"answer-detail"
onClick=
{
()
=>
{
checkAnswerDetail
(
record
);
}
}
>
答题详情
</
div
>
</
When
>
<
Otherwise
>
-
</
Otherwise
>
</
Choose
>
);
},
},
];
function
onChange
(
pagination
:
any
,
filters
:
any
,
sorter
:
any
,
extra
:
any
)
{
setfield
(
sorter
.
field
);
setOrder
(
sorter
.
order
);
console
.
log
(
sorter
.
field
,
sorter
.
order
,
(
orderEnum
as
any
)[
sorter
.
field
]);
let
_query
:
any
=
{
...
queryRef
.
current
};
_query
.
order
=
(
orderEnum
as
any
)[
sorter
.
field
][
sorter
.
order
];
setQuery
(
_query
);
}
function
download
()
{
Service
.
Hades
(
"public/hades/exportExamData"
,
{
// ...query,
examId
:
props
.
examId
,
exportDataType
:
"EXAM_USER_DATA"
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
const
dom
=
(
document
as
any
).
getElementById
(
"load-play-back-excel"
);
dom
.
setAttribute
(
"href"
,
res
.
result
);
dom
.
click
();
});
}
//查看答题详情
function
checkAnswerDetail
(
record
:
any
)
{
const
{
paperId
,
userExamState
}
=
props
.
examDetail
?.
examPaper
;
const
{
userId
}
=
record
;
window
.
RCHistory
.
push
({
pathname
:
`/test-detail/
${
props
.
examId
}
?paperId=
${
paperId
}
&userExamState=
${
userExamState
}
&userId=
${
userId
}
`
,
});
}
return
(
<
div
className=
"rr"
>
<
a
target=
"_blank"
download
id=
"load-play-back-excel"
style=
{
{
position
:
"absolute"
,
left
:
"-10000px"
}
}
>
111
</
a
>
<
div
className=
"dataPanal"
>
<
div
className=
"item"
>
<
div
className=
"num"
>
{
useData
.
joinCnt
||
0
}
</
div
>
<
div
className=
"percent"
></
div
>
<
div
className=
"subTitle"
>
参与人数
</
div
>
</
div
>
<
div
className=
"item"
>
<
div
className=
"num"
>
{
useData
.
finishCnt
||
0
}
</
div
>
<
div
className=
"percent"
>
占比
{
parseInt
(
((
useData
.
finishCnt
||
0
)
/
(
useData
.
joinCnt
||
1
))
*
100
+
""
)
}
%
</
div
>
<
div
className=
"subTitle"
>
完成考试数 (人)
</
div
>
</
div
>
<
div
className=
"item"
>
<
div
className=
"num"
>
{
useData
.
passCnt
||
0
}
</
div
>
<
div
className=
"percent"
>
占比
{
parseInt
(
((
useData
.
passCnt
||
0
)
/
(
useData
.
finishCnt
||
1
))
*
100
+
""
)
}
%
</
div
>
<
div
className=
"subTitle"
>
及格数 (人)
</
div
>
</
div
>
<
div
className=
"item"
>
<
div
className=
"num"
>
{
useData
.
averageScore
||
0
}
</
div
>
<
div
className=
"percent"
>
总分
{
props
.
examDetail
?.
examPaper
?.
totalScore
}
</
div
>
<
div
className=
"subTitle"
>
平均分
</
div
>
</
div
>
<
div
className=
"item"
>
<
div
className=
"num"
>
{
" "
}
{
window
.
formatHourTime
(
useData
.
averageDuration
||
0
)
}{
" "
}
</
div
>
<
div
className=
"percent"
></
div
>
<
div
className=
"subTitle"
>
平均用时
</
div
>
</
div
>
</
div
>
<
div
className=
"xm-search-filter"
style=
{
{
marginTop
:
"24px"
}
}
>
<
div
style=
{
{
display
:
"flex"
}
}
>
<
div
className=
"search-condition"
>
<
div
className=
"search-condition__item"
>
<
span
className=
"search-name"
>
学员:
</
span
>
<
Search
value=
{
query
.
examName
}
className=
"search-input"
placeholder=
"搜索学员名或手机号"
onChange=
{
(
e
)
=>
{
const
_query
=
{
...
query
};
_query
.
searchKey
=
e
.
target
.
value
;
setQuery
(
_query
);
}
}
onSearch=
{
()
=>
{}
}
enterButton=
{
<
span
className=
"icon iconfont"
>

</
span
>
}
/>
</
div
>
<
div
className=
"search-condition__item"
>
<
span
className=
"search-name"
>
学员类型:
</
span
>
<
Select
value=
{
query
.
userSource
}
placeholder=
"请选择学员类型"
onChange=
{
(
val
)
=>
{
const
_query
=
{
...
query
};
_query
.
userSource
=
val
;
setQuery
(
_query
);
}
}
className=
"search-input"
allowClear
>
{
Object
.
keys
(
userTypeEnum
).
map
((
key
:
any
)
=>
{
return
(
<
Option
value=
{
key
}
key=
{
key
}
>
{
(
userTypeEnum
as
any
)[
key
]
}
</
Option
>
);
})
}
</
Select
>
</
div
>
<
div
className=
"search-condition__item"
>
<
span
className=
"search-name"
>
考试状态:
</
span
>
<
Select
value=
{
query
.
userExamState
}
placeholder=
"请选择考试状态"
onChange=
{
(
val
)
=>
{
const
_query
=
{
...
query
};
_query
.
userExamState
=
val
;
setQuery
(
_query
);
}
}
className=
"search-input"
allowClear
>
{
Object
.
keys
(
userExamStateEnum
).
map
((
key
:
any
)
=>
{
return
(
<
Option
value=
{
key
}
key=
{
key
}
>
{
(
userExamStateEnum
as
any
)[
key
]
}
</
Option
>
);
})
}
</
Select
>
</
div
>
</
div
>
<
div
className=
"reset-fold-area"
>
<
Tooltip
title=
"清空筛选"
>
<
span
className=
"resetBtn iconfont icon"
onClick=
{
()
=>
{
setfield
(
""
);
setQuery
({
current
:
1
,
size
:
10
});
}
}
>

{
" "
}
</
span
>
</
Tooltip
>
</
div
>
</
div
>
</
div
>
{
!!
allData
&&
(
<
Button
style=
{
{
marginBottom
:
12
}
}
onClick=
{
download
}
>
导出
</
Button
>
)
}
<
div
className=
"content analysic-content"
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
}
}
bordered
size=
"small"
rowClassName=
"analysic-content-row"
columns=
{
columns
}
dataSource=
{
list
}
onChange=
{
onChange
}
pagination=
{
false
}
></
XMTable
>
{
total
>
0
&&
(
<
PageControl
size=
"small"
current=
{
query
.
current
-
1
}
pageSize=
{
query
.
size
}
total=
{
total
}
toPage=
{
(
page
:
any
)
=>
{
console
.
log
(
page
);
let
_query
:
any
=
{
...
queryRef
.
current
};
_query
.
current
=
page
+
1
;
setQuery
(
_query
);
}
}
/>
)
}
</
div
>
</
div
>
);
}
export
default
DataAnalysic
;
src/modules/task-center/data-center/components/WholeData.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-05 11:26:25
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 18:27:06
* @Description: 个人学习详情-全部tab页
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Collapse
,
Progress
}
from
'antd'
;
import
'./WholeData.less'
;
import
ENUM
from
'../../enum'
;
const
{
Panel
}
=
Collapse
;
function
WholeData
(
props
)
{
const
SortConvert
=
[
'一'
,
'二'
,
'三'
,
'四'
,
'五'
,
'六'
,
'七'
,
'八'
,
'九'
,
'十'
];
const
courseStateShow
=
{
UN_START
:
{
title
:
'待开播'
,
},
STARTING
:
{
title
:
'直播中'
,
},
FINISH
:
{
title
:
'回放'
,
},
EXPIRED
:
{
title
:
'未成功开课'
,
},
};
const
[
stageCustomerList
,
setStageCustomerList
]
=
useState
([]);
useEffect
(()
=>
{
setStageCustomerList
(
props
.
detail
.
stageCustomerVOList
);
},
[
props
]);
// 渲染阶段信息
function
renderStageInfo
(
item
,
index
)
{
return
(
<
div
className=
'stage-info__item'
>
<
span
className=
'stage-name'
>
{
SortConvert
[
index
]
}
、
{
item
.
stageName
}
</
span
>
<
span
className=
'extra-info'
>
(
{
item
.
learnFinishNum
||
0
}
/
{
item
.
learnAllNum
||
item
.
contentVOList
.
length
}
)
</
span
>
</
div
>
);
}
// 渲染学习内容信息
function
renderContentInfo
(
contentItem
,
contentIndex
,
index
)
{
const
{
contentName
,
contentType
,
courseChapterNum
,
courseState
,
learnFinishPercentage
,
courseType
}
=
contentItem
;
return
(
<
div
className=
'content-info__item'
>
<
div
className=
'basic-info'
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
courseType
||
contentType
]
}
/>
<
span
className=
'content-name'
>
{
contentIndex
+
1
}
.
{
index
+
1
}
{
contentName
}
</
span
>
{
courseType
===
'LIVE'
&&
<
span
className=
'extra-info'
>
{
courseStateShow
[
courseState
].
title
}
</
span
>
}
{
courseType
===
'VOICE'
&&
<
span
className=
'extra-info'
>
(共
{
courseChapterNum
||
1
}
小节)
</
span
>
}
</
div
>
<
div
className=
'percent-info'
>
{
learnFinishPercentage
===
100
?
(
<
span
className=
'icon iconfont'
>

</
span
>
)
:
(
<
Progress
width=
{
20
}
strokeWidth=
{
12
}
type=
'circle'
trailColor=
'#EAEAEA'
strokeColor=
{
{
'0%'
:
'#38B7F3'
,
'100%'
:
'#1A80E2'
,
}
}
percent=
{
learnFinishPercentage
||
0
}
/>
)
}
<
span
className=
'text'
>
{
learnFinishPercentage
===
100
?
'已完成'
:
`${learnFinishPercentage || 0}%`
}
</
span
>
</
div
>
</
div
>
);
}
return
(
<
div
className=
'whole-data-container'
>
<
Collapse
ghost
>
{
stageCustomerList
?.
length
>
0
&&
stageCustomerList
.
map
((
item
,
index
)
=>
{
return
(
<
Panel
header=
{
renderStageInfo
(
item
,
index
)
}
key=
{
index
}
>
{
item
.
contentVOList
.
map
((
contentItem
,
contentIndex
)
=>
{
return
renderContentInfo
(
contentItem
,
contentIndex
,
index
);
})
}
</
Panel
>
);
})
}
</
Collapse
>
</
div
>
);
}
export
default
WholeData
;
src/modules/task-center/data-center/components/WholeData.less
0 → 100644
View file @
b427be83
.whole-data-container {
.ant-collapse-header {
padding: 15px 16px !important;
background-color: #f7f8f9;
}
.stage-info {
&__item {
width: calc(100% - 24px);
display: inline-flex;
align-items: center;
line-height: 20px;
.stage-name {
color: #333333;
}
.extra-info {
margin-left: 8px;
color: #666666;
}
}
}
.content-info {
&__item {
padding: 14px 16px;
margin-left: 40px;
border-bottom: 1px dotted #e8e8e8;
vertical-align: middle;
display: flex;
justify-content: space-between;
* {
vertical-align: middle;
}
.basic-info {
.content-name {
margin-left: 12px;
color: #333333;
}
.extra-info {
margin-left: 8px;
color: #999999;
}
img {
width: 20px;
height: 20px;
}
}
.percent-info {
width: 70px;
.ant-progress-text {
display: none;
}
.icon {
color: #2966ff;
font-size: 20px;
}
.text {
margin-left: 6px;
color: #666666;
}
}
}
}
}
src/modules/task-center/data-center/components/course.less
0 → 100644
View file @
b427be83
.courseTabContent{
padding-bottom: 24px;
.tips{
// height: 48px;
background: #F7F8F9;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
padding: 14px 16px;
}
.coursecontent{
margin-top: 16px;
margin-bottom: 16px;
.title{
padding: 14px 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
background: #F7F8F9;
border-radius: 2px;
cursor: pointer;
.icon{
color: rgba(153, 153, 153, 1);
transform: scale(0.8);
display: inline-block;
transform-origin: 50% 50%;
margin-right: 4px;
&.open{
transform:rotate(180deg) scale(0.8);
}
}
}
.taskItemList{
margin-left: 64px;
.item{
padding: 16px 0px 16px 16px;
border-bottom: 1px dashed #E8E8E8;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
.name{
img{
width: 20px;
position: relative;
top: -2px;
}
}
&.noBorder{
border:none;
}
.desc{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin-left: 8px;
}
}
}
}
.expired{
.title{
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 22px;
}
.desc{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
margin: 12px 0;
}
.list{
.item{
display: flex;
justify-content: space-between;
background: #F7F8F9;
border-radius: 2px;
padding: 16px;
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 20px;
span{
margin-right: 12px;
}
.na{
color: #333333;
}
.ope{
color: rgba(41, 102, 255, 1);
cursor: pointer;
}
}
}
}
}
src/modules/task-center/data-center/components/dataAnalysic.less
0 → 100644
View file @
b427be83
.dataAnalysic {
.titleBox {
position: relative;
font-size: 19px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
background: #ffffff;
&::before {
width: 4px;
height: 12px;
content: '';
background-image: linear-gradient(#2966ff 83.5%, #0acca4 16.5%);
display: inline-block;
margin-right: 8px;
}
}
.ant-tabs-content-holder {
margin-top: 8px;
}
}
src/modules/task-center/data-center/components/study.less
0 → 100644
View file @
b427be83
.study_Table{
}
\ No newline at end of file
src/modules/task-center/data-center/components/userData.less
0 → 100644
View file @
b427be83
.dataPanal {
border-radius: 4px;
border: 1px solid #e8e8e8;
display: flex;
.item {
text-align: center;
// width: 29.9%;
position: relative;
flex: 1;
.num {
font-size: 26px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 26px;
margin-top: 12px;
}
.percent {
margin-top: 6px;
font-size: 12px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #999999;
line-height: 17px;
height: 20px;
margin-bottom: 18px;
}
.subTitle {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 12px;
}
.type {
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #333333;
line-height: 20px;
span {
color: rgba(153, 153, 153, 1);
}
.icon {
color: rgba(204, 204, 204, 1);
font-size: 16px;
margin-right: 4px;
position: relative;
top: 1px;
}
}
&:after {
content: '';
width: 0px;
height: 40px;
position: absolute;
width: 1px;
background-color: rgba(232, 232, 232, 1);
top: 40px;
right: 0px;
}
&:last-child {
&:after {
display: none;
}
}
}
.exstatus {
width: 4px;
height: 4px;
background: rgb(35, 143, 255);
display: inline-block;
border-radius: 50%;
position: relative;
top: -4px;
}
}
.answer-detail {
color: rgb(35, 143, 255);
}
.analysic-content {
.ant-table-bordered .ant-table-tbody tr {
&.analysic-content-row {
height: 50px;
}
}
}
src/modules/task-center/data-center/index.less
0 → 100644
View file @
b427be83
.train-data-center{
.content{
margin: 0 16px;
}
.infoBox{
background: #FFFFFF;
box-shadow: 0px 10px 20px 0px rgba(0, 0, 0, 0.05);
border-radius: 2px;
display: flex;
height: 141px;
justify-content: space-between;
margin: 0 0px 16px;
.left{
display: flex;
.banner{
padding: 16px;
img{
width: 194px;
height: 109px;
}
}
.textBox{
padding-top: 1px;
.nameBox{
margin-top: 12px;
margin-bottom: 34px;
display: flex;
.name{
font-size: 18px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #333333;
line-height: 25px;
}
.status{
padding: 0px 8px;
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #999999;
line-height: 20px;
text-align: center;
margin-left: 24px;
position: relative;
top: 2px;
height: 20px;
}
}
.info{
margin-bottom: 12px;
.icon{
position: relative;
top: -2px;
margin-right: 8px;
img{
width: 20px;
}
}
span,.item{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
display: inline-block;
}
.item{
margin-right: 24px;
}
}
}
}
.right{
display: flex;
margin-right: 32px;
.prog{
width: 85px;
margin-top: 27px;
margin-right: 24px;
position: relative;
.wcl{
font-size: 16px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #666666;
line-height: 22px;
text-align: center;
// left: 0px;
// top: 20px;
// width: 100%;
// height: 100%;
// display: none;
// position: absolute;
// z-index: 1;
}
// &:hover{
// .wcl{
// display: block;
// }
// }
}
.num{
margin-top: 27px;
.item{
font-size: 14px;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #666666;
line-height: 20px;
margin-bottom: 12px;
}
}
}
}
}
\ No newline at end of file
src/modules/task-center/enum.ts
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-03 18:10:15
* @LastEditors: wufan
* @LastEditTime: 2021-08-09 18:24:21
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
const
ENUM
:
any
=
{
trainStatus
:
{
UN_START
:
{
text
:
"未开始"
,
color
:
"rgba(255, 178, 0, 1)"
,
background
:
"rgba(255, 178, 0, 0.1)"
,
},
STARTING
:
{
text
:
"进行中"
,
color
:
"rgba(41, 102, 255, 1)"
,
background
:
"rgba(41, 102, 255, 0.1)"
,
},
FINISH
:
{
text
:
"已结束"
,
color
:
"rgba(153, 153, 153, 1)"
,
background
:
"rgba(153, 153, 153, 0.1)"
,
},
},
learnState
:
{
UN_FINISH
:
{
text
:
"未完成"
,
},
FINISH
:
{
text
:
"已完成"
,
},
OVERDUE
:
{
text
:
"已逾期"
,
},
},
courseStateShow
:
{
UN_START
:
{
title
:
'待开播'
,
},
STARTING
:
{
title
:
'直播中'
,
},
FINISH
:
{
title
:
'回放'
,
},
EXPIRED
:
{
title
:
'未成功开课'
,
},
},
LearnState
:
{
UN_PLAY
:
{
text
:
'未开始'
,
},
UNDER_WAY
:
{
text
:
'进行中'
,
},
FINISH
:
{
text
:
'已完成'
,
},
},
LearningContentIcon
:
{
COURSE
:
'https://image.xiaomaiketang.com/xm/6C2GjSpnDp.png'
,
LIVE
:
'https://image.xiaomaiketang.com/xm/jyFhCtaKfi.png'
,
VOICE
:
'https://image.xiaomaiketang.com/xm/2T2k5Tbmpy.png'
,
PICTURE
:
'https://image.xiaomaiketang.com/xm/yzjNwGX6TY.png'
,
EXAM
:
'https://image.xiaomaiketang.com/xm/fCDPp2Eenc.png'
,
HOMEWORK
:
'https://image.xiaomaiketang.com/xm/hShsAzzppZ.png'
,
},
// index to 中文序号
IndexToSort
:
{
1
:
'一'
,
2
:
'二'
,
3
:
'三'
,
4
:
'四'
,
5
:
'五'
,
6
:
'六'
,
7
:
'七'
,
8
:
'八'
,
9
:
'九'
,
10
:
'十'
,
11
:
'十一'
}
}
export
default
ENUM
\ No newline at end of file
src/modules/task-center/train-task/AddTrainTask.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-07-29 13:57:03
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 10:53:45
* @Description: 任务中心-培训任务-新建页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
,
useRef
}
from
'react'
;
import
{
Button
,
message
,
Modal
}
from
'antd'
;
import
ShowTips
from
'@/components/ShowTips'
;
import
Breadcrumbs
from
'@/components/Breadcrumbs'
;
import
BasicInfo
from
'./components/BasicInfo'
;
import
TrainContent
from
'./components/TrainContent'
;
import
User
from
'@/common/js/user'
;
import
_
from
'underscore'
;
import
'./AddTrainTask.less'
;
import
Upload
from
'@/core/upload'
;
import
{
randomString
}
from
'@/domains/basic-domain/utils'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
import
Bus
from
'@/core/bus'
;
import
$
from
'jquery'
;
function
AddTrainTask
()
{
const
type
=
window
.
getParameterByName
(
'type'
);
const
taskId
=
window
.
getParameterByName
(
'taskId'
);
const
taskState
=
window
.
getParameterByName
(
'taskState'
);
const
defaultCover
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
;
const
DEFAULT_BASIC_INFO
=
{
createId
:
User
.
getStoreUserId
(),
taskName
:
''
,
// 培训任务名称
coverUrl
:
defaultCover
,
coverId
:
null
,
helpStoreUserIds
:
[
{
checkedId
:
User
.
getStoreUserId
(),
checkedName
:
User
.
getStoreUserName
(),
},
],
// 指定协同者id
timeType
:
'FOREVER'
,
// 培训时间,默认永久有效
startTime
:
null
,
// 固定时间段-开始时间
endTime
:
null
,
// 固定时间段-结束时间
learnType
:
'FREEDOM'
,
// 学习模式,默认自由学习
assignList
:
[],
// 指派列表-assignId assignType
introduce
:
null
,
// 培训目的
loadintroduce
:
false
,
};
const
DEFAULT_STAGE_LIST
=
[
{
stageName
:
'阶段一'
,
contentList
:
[],
check
:
false
,
sequence
:
1
,
},
];
const
DEFAULT_ORIGIN_STAGE_LIST
=
[
{
stageName
:
'阶段一'
,
contentList
:
[],
check
:
false
,
sequence
:
1
,
},
];
const
[
activeStep
,
setActiveStep
]
=
useState
(
'BASIC_INFO'
);
const
[
basicInfo
,
setBasicInfo
]
=
useState
(
DEFAULT_BASIC_INFO
);
const
[
stageList
,
setStageList
]
=
useState
(
DEFAULT_STAGE_LIST
);
const
[
percentCompleteLive
,
setPercentCompleteLive
]
=
useState
(
80
);
// 完成百分比
const
[
percentCompleteVideo
,
setPercentCompleteVideo
]
=
useState
(
80
);
// 完成百分比
const
[
percentCompletePicture
,
setPercentCompletePicture
]
=
useState
(
80
);
// 完成百分比
const
[
startCheck
,
setStartCheck
]
=
useState
(
false
);
// 是否启动校验
const
basicInfoRef
=
useRef
(
null
);
const
[
originBasicInfo
,
setOriginBasicInfo
]
=
useState
(
DEFAULT_BASIC_INFO
);
const
[
originStageList
,
setOriginStageList
]
=
useState
(
DEFAULT_ORIGIN_STAGE_LIST
);
const
[
originPercentCompleteLive
,
setOriginPercentCompleteLive
]
=
useState
(
80
);
// 完成百分比
const
[
originPercentCompleteVideo
,
setOriginPercentCompleteVideo
]
=
useState
(
80
);
// 完成百分比
const
[
originPercentCompletePicture
,
setOriginPercentCompletePicture
]
=
useState
(
80
);
// 完成百分比
useEffect
(()
=>
{
basicInfoRef
.
current
=
basicInfo
;
},
[
basicInfo
]);
useEffect
(()
=>
{
if
(
type
===
'edit'
)
{
initTaskData
();
// 编辑回显数据详情
function
initTaskData
()
{
TaskCenterService
.
getTrainingTaskDetail
({
taskId
,
}).
then
((
res
)
=>
{
const
{
result
:
{
created
,
createId
,
taskName
,
courseMediaVOS
,
helpStoreUsers
,
timeType
,
startTime
,
endTime
,
learnType
,
assignList
,
percentCompleteLive
,
percentCompletePicture
,
percentCompleteVideo
,
trainingStageList
,
},
}
=
res
;
const
_assignList
=
assignList
?
assignList
.
map
((
item
)
=>
{
item
.
checkedId
=
item
.
assignId
;
item
.
checkedName
=
item
.
assignName
;
item
.
checkedType
=
item
.
assignType
;
return
item
;
})
:
[];
const
coverInfo
=
courseMediaVOS
.
filter
((
item
)
=>
item
.
contentType
===
'COVER'
)[
0
];
const
coverUrl
=
coverInfo
?
coverInfo
.
mediaUrl
:
defaultCover
;
const
coverId
=
coverInfo
?
coverInfo
.
mediaContent
:
null
;
const
_helpStoreUserIds
=
helpStoreUsers
.
map
((
item
)
=>
{
item
.
checkedName
=
item
.
storeUserName
;
item
.
checkedId
=
item
.
storeUserId
;
return
item
;
});
const
ITEM_BASIC_INFO
=
{
createId
,
assignList
:
_assignList
,
taskName
,
coverUrl
,
coverId
,
helpStoreUserIds
:
_helpStoreUserIds
,
timeType
,
startTime
:
timeType
===
'FOREVER'
?
created
:
startTime
,
endTime
,
learnType
,
};
const
_stageList
=
trainingStageList
.
map
((
item
)
=>
{
item
.
contentList
=
item
.
contentVOList
;
item
.
type
=
'text'
;
return
item
;
});
const
_originStageList
=
_stageList
.
map
((
item
)
=>
Object
.
assign
({},
item
));
const
introduceInfo
=
courseMediaVOS
.
filter
((
item
)
=>
item
.
contentType
===
'INTRO'
)[
0
];
setBasicInfo
({
...
basicInfoRef
.
current
,
...
ITEM_BASIC_INFO
,
loadintroduce
:
!
introduceInfo
});
setOriginBasicInfo
({
...
basicInfoRef
.
current
,
...
ITEM_BASIC_INFO
,
loadintroduce
:
!
introduceInfo
});
setPercentCompleteLive
(
percentCompleteLive
);
setPercentCompleteVideo
(
percentCompleteVideo
);
setPercentCompletePicture
(
percentCompletePicture
);
setOriginPercentCompleteLive
(
percentCompleteLive
);
setOriginPercentCompleteVideo
(
percentCompleteVideo
);
setOriginPercentCompletePicture
(
percentCompletePicture
);
setStageList
(
_stageList
);
setOriginStageList
(
_originStageList
);
introduceInfo
&&
getTextDetail
(
'introduce'
,
introduceInfo
);
});
}
}
},
[
taskId
,
type
]);
// 获取培训目的内容
function
getTextDetail
(
key
,
info
)
{
if
(
info
.
mediaType
===
'RESOURCE_ID'
)
{
$
.
ajax
({
data
:
{},
type
:
'GET'
,
url
:
info
.
mediaUrl
,
contentType
:
'application/x-www-form-urlencoded; charset=UTF-8'
,
success
:
(
res
)
=>
{
setBasicInfo
({
...
basicInfoRef
.
current
,
[
key
]:
res
,
[
`load
${
key
}
`
]:
true
,
});
setOriginBasicInfo
({
...
basicInfoRef
.
current
,
[
key
]:
res
,
[
`load
${
key
}
`
]:
true
,
});
},
});
}
else
if
(
info
.
mediaType
===
'TEXT'
)
{
setBasicInfo
({
...
basicInfoRef
.
current
,
[
key
]:
info
.
mediaContent
,
[
`load
${
key
}
`
]:
true
,
});
setOriginBasicInfo
({
...
basicInfoRef
.
current
,
[
key
]:
info
.
mediaContent
,
[
`load
${
key
}
`
]:
true
,
});
}
}
// 渲染底部操作按钮
function
renderFooter
()
{
return
(
<
Choose
>
<
When
condition=
{
activeStep
===
'BASIC_INFO'
}
>
<
div
className=
'footer shrink-footer'
>
<
Button
onClick=
{
handleGoBack
}
>
取消
</
Button
>
<
Button
onClick=
{
()
=>
handleSubmit
(
'NO'
)
}
>
保存
</
Button
>
<
Button
type=
'primary'
onClick=
{
()
=>
setActiveStep
(
'TRAIN_CONTENT'
)
}
>
下一步
</
Button
>
</
div
>
</
When
>
<
Otherwise
>
<
div
className=
'footer shrink-footer'
>
<
Button
onClick=
{
handleGoBack
}
>
取消
</
Button
>
<
Button
onClick=
{
()
=>
setActiveStep
(
'BASIC_INFO'
)
}
>
上一步
</
Button
>
<
Button
onClick=
{
()
=>
handleSubmit
(
'NO'
)
}
>
保存
</
Button
>
<
Button
type=
'primary'
onClick=
{
()
=>
handleSubmit
(
'YES'
)
}
>
保存并发布
</
Button
>
</
div
>
</
Otherwise
>
</
Choose
>
);
}
// 确认保存新建
function
submitRemote
(
introduceId
,
issue
)
{
const
{
createId
,
assignList
,
endTime
,
helpStoreUserIds
,
learnType
,
startTime
,
taskName
,
timeType
,
coverId
}
=
basicInfo
;
let
_scheduleMediaRequests
=
[];
if
(
coverId
)
{
_scheduleMediaRequests
.
push
({
contentType
:
'COVER'
,
mediaContent
:
coverId
,
mediaType
:
'PICTURE'
,
});
}
if
(
introduceId
)
{
_scheduleMediaRequests
.
push
({
contentType
:
'INTRO'
,
mediaContent
:
introduceId
,
mediaType
:
'RESOURCE_ID'
,
});
}
const
_stageList
=
stageList
.
map
((
item
,
index
)
=>
{
delete
item
.
contentVOList
;
delete
item
.
check
;
delete
item
.
type
;
delete
item
.
liveFailure
;
item
.
sequence
=
index
+
1
;
return
item
;
});
const
_helpStoreUserIds
=
helpStoreUserIds
.
map
((
item
)
=>
{
return
item
.
checkedId
;
});
const
_assignList
=
assignList
.
map
((
item
)
=>
{
return
{
assignId
:
item
.
checkedId
,
assignType
:
item
.
checkedType
,
};
});
const
commonParams
=
{
assignList
:
_assignList
,
createId
,
endTime
,
helpStoreUserIds
:
_helpStoreUserIds
,
// 协同者集合
issueState
:
issue
,
// 是否发布
learnType
,
// 学习模式
scheduleMediaRequests
:
_scheduleMediaRequests
,
startTime
,
storeId
:
User
.
getStoreId
(),
taskName
,
timeType
,
percentCompleteLive
,
percentCompletePicture
,
percentCompleteVideo
,
introduceId
,
trainingStageList
:
_stageList
,
};
if
(
type
===
'edit'
)
{
TaskCenterService
.
updateTrainingTask
({
...
commonParams
,
id
:
taskId
}).
then
((
res
)
=>
{
message
.
success
(
'保存成功'
);
RCHistory
.
goBack
();
});
}
else
{
TaskCenterService
.
createTrainingTask
(
commonParams
).
then
((
res
)
=>
{
message
.
success
(
'保存成功'
);
RCHistory
.
goBack
();
});
}
Bus
.
trigger
(
'getTrainingTaskPage'
);
Bus
.
trigger
(
'getStoreTaskNum'
);
}
// 保存
function
handleSubmit
(
issue
)
{
setStartCheck
(
true
);
const
{
taskName
,
assignList
,
timeType
,
startTime
,
endTime
}
=
basicInfo
;
if
(
!
taskName
)
{
activeStep
===
'TRAIN_CONTENT'
&&
setActiveStep
(
'BASIC_INFO'
);
return
message
.
warning
(
'请输入培训任务名称'
);
}
if
(
timeType
===
'VALIDITY'
)
{
if
(
!
startTime
)
{
return
message
.
warning
(
'请选择开始时间'
);
}
if
(
!
endTime
)
{
return
message
.
warning
(
'请选择结束时间'
);
}
if
((
type
===
'add'
||
taskState
===
'UN_START'
)
&&
startTime
<
new
Date
().
getTime
())
{
return
message
.
warning
(
'开始时间不能早于现在'
);
}
if
(
!
endTime
>
new
Date
().
getTime
())
{
return
message
.
warning
(
'结束时间不能早于现在'
);
}
}
if
(
assignList
.
length
===
0
)
{
activeStep
===
'TRAIN_CONTENT'
&&
setActiveStep
(
'BASIC_INFO'
);
return
message
.
warning
(
'请选择指派学员'
);
}
if
(
stageList
.
length
===
0
)
{
activeStep
===
'BASIC_INFO'
&&
setActiveStep
(
'TRAIN_CONTENT'
);
return
message
.
warning
(
'请添加阶段'
);
}
const
stageNameEmpty
=
stageList
.
filter
((
item
)
=>
!
item
.
stageName
);
if
(
stageNameEmpty
.
length
>
0
)
{
activeStep
===
'BASIC_INFO'
&&
setActiveStep
(
'TRAIN_CONTENT'
);
return
message
.
warning
(
'请输入阶段名称'
);
}
const
stageNameArr
=
stageList
.
map
((
item
)
=>
item
.
stageName
);
const
stageNameSet
=
new
Set
(
stageNameArr
);
if
(
stageNameSet
.
size
!==
stageNameArr
.
length
)
{
activeStep
===
'BASIC_INFO'
&&
setActiveStep
(
'TRAIN_CONTENT'
);
return
message
.
warning
(
'阶段名称不能重复'
);
}
if
(
percentCompleteLive
===
''
||
percentCompleteVideo
===
''
||
percentCompletePicture
===
''
)
{
activeStep
===
'BASIC_INFO'
&&
setActiveStep
(
'TRAIN_CONTENT'
);
return
message
.
warning
(
'请输入完成标准'
);
}
if
(
basicInfo
.
introduce
)
{
Upload
.
uploadTextToOSS
(
basicInfo
.
introduce
,
`
${
randomString
()}
.txt`
,
(
introduceId
)
=>
{
submitRemote
(
introduceId
,
issue
);
},
()
=>
{
activeStep
===
'TRAIN_CONTENT'
&&
setActiveStep
(
'BASIC_INFO'
);
message
.
warning
(
'上传培训目的失败'
);
}
);
}
else
{
submitRemote
(
null
,
issue
);
}
}
// 判断基本信息是否修改
function
isEqualBasicInfo
()
{
return
Object
.
entries
(
originBasicInfo
).
toString
()
===
Object
.
entries
(
basicInfo
).
toString
();
}
// 判断培训内容是否修改
function
isEqualStageList
()
{
return
JSON
.
stringify
(
originStageList
)
===
JSON
.
stringify
(
stageList
);
}
// 判断完成标准是否修改
function
isFinishedStandard
()
{
return
(
percentCompleteLive
===
originPercentCompleteLive
&&
percentCompleteVideo
===
originPercentCompleteVideo
&&
percentCompletePicture
===
originPercentCompletePicture
);
}
// 返回、取消
function
handleGoBack
()
{
if
(
!
isEqualBasicInfo
()
||
!
isEqualStageList
()
||
!
isFinishedStandard
())
{
Modal
.
confirm
({
title
:
'确认要返回吗?'
,
content
:
'返回后,本次编辑的内容将不被保存。'
,
okText
:
'确认返回'
,
cancelText
:
'留在本页'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
onOk
:
()
=>
{
window
.
RCHistory
.
goBack
();
},
});
}
else
{
window
.
RCHistory
.
goBack
();
}
}
function
handleChangeBasicInfo
(
field
,
value
)
{
if
(
field
===
'coverUrl'
)
{
setBasicInfo
({
...
basicInfoRef
.
current
,
coverUrl
:
value
.
fileUrl
,
coverId
:
value
.
resourceId
,
});
}
else
if
(
field
===
'trainDate'
)
{
// 固定培训时间,设置起始
setBasicInfo
({
...
basicInfoRef
.
current
,
startTime
:
value
&&
value
[
0
]?.
valueOf
(),
endTime
:
value
&&
value
[
1
]?.
valueOf
(),
});
}
else
{
setBasicInfo
({
...
basicInfoRef
.
current
,
[
field
]:
value
,
});
}
}
function
handleChangeStageInfo
(
field
,
value
)
{
if
(
field
===
'stageList'
)
{
setStageList
(
value
);
}
else
{
switch
(
field
)
{
case
'percentCompleteLive'
:
setPercentCompleteLive
(
value
);
break
;
case
'percentCompleteVideo'
:
setPercentCompleteVideo
(
value
);
break
;
case
'percentCompletePicture'
:
setPercentCompletePicture
(
value
);
break
;
default
:
break
;
}
}
}
return
(
<
div
className=
'page add-train-task'
>
<
Breadcrumbs
navList=
{
type
===
'add'
?
'新建培训任务'
:
'编辑培训任务'
}
goBack=
{
handleGoBack
}
/>
<
div
className=
'box'
>
<
div
className=
'show-tips'
>
<
ShowTips
message=
'请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利'
/>
</
div
>
<
div
className=
'header-tab'
>
<
span
className=
'tab-title'
onClick=
{
()
=>
setActiveStep
(
'BASIC_INFO'
)
}
>
<
span
className=
{
`step-icon ${activeStep === 'BASIC_INFO' ? 'active-icon' : 'default-icon'}`
}
>
1
</
span
>
<
span
style=
{
{
position
:
'relative'
}
}
>
<
span
className=
{
`${activeStep === 'BASIC_INFO' && 'active-text'}`
}
>
基本信息
</
span
>
{
activeStep
===
'BASIC_INFO'
&&
<
span
className=
'active-line'
></
span
>
}
</
span
>
</
span
>
<
span
className=
'next-arrow'
></
span
>
<
span
className=
'tab-title'
onClick=
{
()
=>
setActiveStep
(
'TRAIN_CONTENT'
)
}
>
<
span
className=
{
`step-icon ${activeStep === 'TRAIN_CONTENT' ? 'active-icon' : 'default-icon'}`
}
>
2
</
span
>
<
span
style=
{
{
position
:
'relative'
}
}
>
<
span
className=
{
`${activeStep === 'TRAIN_CONTENT' && 'active-text'}`
}
>
培训内容
</
span
>
{
activeStep
===
'TRAIN_CONTENT'
&&
<
span
className=
'active-line'
></
span
>
}
</
span
>
</
span
>
</
div
>
{
activeStep
===
'BASIC_INFO'
&&
<
BasicInfo
basicInfo=
{
basicInfo
}
startCheck=
{
startCheck
}
onChange=
{
handleChangeBasicInfo
}
/>
}
{
activeStep
===
'TRAIN_CONTENT'
&&
(
<
TrainContent
stageList=
{
stageList
}
basicInfo=
{
basicInfo
}
startCheck=
{
startCheck
}
percentCompleteLive=
{
percentCompleteLive
}
percentCompleteVideo=
{
percentCompleteVideo
}
percentCompletePicture=
{
percentCompletePicture
}
onChange=
{
handleChangeStageInfo
}
/>
)
}
</
div
>
{
renderFooter
()
}
</
div
>
);
}
export
default
AddTrainTask
;
src/modules/task-center/train-task/AddTrainTask.less
0 → 100644
View file @
b427be83
.add-train-task {
.header-tab {
position: relative;
padding: 20px 0 12px 0;
text-align: center;
font-size: 16px;
color: #666666;
line-height: 22px;
border-bottom: 1px solid #e8e8e8;
margin-bottom: 20px;
.tab-title {
position: relative;
cursor: pointer;
&:first-child {
margin-right: 44px;
}
.step-icon {
display: inline-block;
width: 16px;
height: 16px;
border-radius: 50%;
font-size: 12px;
text-align: center;
line-height: 14px;
margin-right: 8px;
&.default-icon {
border: 1px solid #999999;
color: #999999;
}
&.active-icon {
background-color: #2966ff;
border: 1px solid #2966ff;
color: #ffffff;
}
}
.active-text {
color: #2966ff;
}
.active-line {
position: absolute;
width: 32px;
height: 2px;
background: #2966ff;
top: 34px;
left: 16px;
z-index: 999;
}
}
&::after {
content: ' ';
height: 10px;
width: 10px;
border-width: 2px 2px 0 0;
border-color: #999999;
border-style: solid;
transform: matrix(0.71, 0.71, -0.71, 0.71, 0, 0);
position: absolute;
top: 50%;
left: calc(50% - 5px);
}
}
.footer {
position: fixed;
left: 196px;
bottom: 0;
height: 58px;
width: ~'calc(100% - 218px)';
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 72px;
background: #fff;
border-top: 1px solid #e8e8e8;
z-index: 9999;
.ant-btn {
margin-left: 10px;
}
}
}
src/modules/task-center/train-task/TrainTaskPage.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-07-28 11:25:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 12:36:21
* @Description: 任务中心-培训任务
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
TrainFilter
from
'./components/TrainFilter'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
TrainList
from
'./components/TrainList'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
import
DataCenter
from
'../data-center/Index'
;
import
User
from
'@/common/js/user'
;
import
Bus
from
'@/core/bus'
;
function
TrainTaskPage
(
props
)
{
const
[
trainListData
,
setTrainListData
]
=
useState
([]);
// 培训任务列表
const
[
query
,
setQuery
]
=
useState
({
current
:
1
,
endTime
:
null
,
issueState
:
'ALL'
,
// 发布状态
myAssist
:
false
,
// 是否由我协同
size
:
10
,
sortMap
:
{
UPDATED
:
'SORT_DESC'
},
// 排序(默认更新时间倒序)
startTime
:
null
,
storeId
:
User
.
getStoreId
(),
storeUserId
:
User
.
getStoreUserId
(),
taskName
:
''
,
});
const
[
totalCount
,
setTotalCount
]
=
useState
(
0
);
// 总数
const
[
storeTaskNum
,
setStoreTaskNum
]
=
useState
({});
const
{
match
}
=
props
;
useEffect
(()
=>
{
getTrainingTaskPage
();
},
[
query
]);
useEffect
(()
=>
{
getStoreTaskNum
();
initPageData
();
return
()
=>
{
removePageData
();
};
},
[]);
useEffect
(()
=>
{},
[]);
const
initPageData
=
()
=>
{
Bus
.
bind
(
'getTrainingTaskPage'
,
(
filterData
)
=>
{
getTrainingTaskPage
(
filterData
);
});
Bus
.
bind
(
'getStoreTaskNum'
,
getStoreTaskNum
);
};
const
removePageData
=
()
=>
{
Bus
.
unbind
(
'getTrainingTaskPage'
,
getTrainingTaskPage
);
Bus
.
unbind
(
'getStoreTaskNum'
,
getStoreTaskNum
);
};
// 获取计划列表
function
getTrainingTaskPage
(
filterData
)
{
const
_query
=
{
...
query
,
...
filterData
};
if
(
_query
.
issueState
===
'ALL'
)
{
delete
_query
.
issueState
;
}
TaskCenterService
.
getTrainingTaskPage
(
_query
).
then
((
res
)
=>
{
const
{
result
:
{
records
=
[],
total
},
}
=
res
;
setTrainListData
(
records
);
setTotalCount
(
total
);
});
}
// 获取学院任务数量
function
getStoreTaskNum
()
{
TaskCenterService
.
getStoreTaskNum
({
storeId
:
User
.
getStoreId
()
}).
then
((
res
)
=>
{
setStoreTaskNum
(
res
.
result
);
});
}
// 搜索条件修改
function
queryChange
(
_query
)
{
setQuery
({
...
query
,
...
_query
});
}
return
(
<
div
className=
'page'
>
<
div
className=
'content-header'
>
培训任务
</
div
>
<
div
className=
'box'
>
<
TrainFilter
onChange=
{
queryChange
}
/>
<
TrainList
trainListData=
{
trainListData
}
storeTaskNum=
{
storeTaskNum
}
query=
{
query
}
totalCount=
{
totalCount
}
onChange=
{
queryChange
}
/>
</
div
>
<
Route
path=
{
`${match.url}/data/:taskId`
}
component=
{
DataCenter
}
/>
</
div
>
);
}
export
default
withRouter
(
TrainTaskPage
);
src/modules/task-center/train-task/components/BasicInfo.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-07-29 14:32:24
* @LastEditors: yuananting
* @LastEditTime: 2021-08-17 14:50:30
* @Description: 任务中心-培训任务-新建-基本信息
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Form
,
Button
,
Input
,
Space
,
DatePicker
,
Radio
,
Tag
,
message
,
Tooltip
}
from
'antd'
;
import
SelectPrepareFileModal
from
'@/modules/prepare-lesson/modal/SelectPrepareFileModal'
;
import
Upload
from
'@/core/upload'
;
import
GraphicsEditor
from
'@/modules/course-manage/components/GraphicsEditor'
;
import
ImgClipModal
from
'@/components/ImgClipModal'
;
import
moment
from
'moment'
;
import
'./BasicInfo.less'
;
import
ChooseAssignorModal
from
'../modal/ChooseAssignorModal'
;
import
ChooseCollaboratorModal
from
'../modal/ChooseCollaboratorModal'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
const
{
RangePicker
}
=
DatePicker
;
const
FormItem
=
Form
.
Item
;
function
BasicInfo
(
props
)
{
const
taskState
=
window
.
getParameterByName
(
'taskState'
);
const
type
=
window
.
getParameterByName
(
'type'
);
const
originTimeType
=
window
.
getParameterByName
(
'timeType'
);
const
{
basicInfo
,
startCheck
}
=
props
;
const
{
createId
,
taskName
,
coverUrl
,
helpStoreUserIds
,
timeType
,
startTime
,
endTime
,
learnType
,
assignList
,
introduce
,
loadintroduce
}
=
basicInfo
;
const
depAssignList
=
assignList
.
filter
((
item
)
=>
item
.
checkedType
!==
'CUSTOMER'
);
const
userAssignList
=
assignList
.
filter
((
item
)
=>
item
.
checkedType
===
'CUSTOMER'
);
const
[
imageFile
,
setImageFile
]
=
useState
(
null
);
// 需要被截取的图片
const
[
showSelectFileModal
,
setShowSelectFileModal
]
=
useState
(
false
);
const
[
imgClipVisible
,
setImgClipVisible
]
=
useState
(
false
);
// 当前是否使用的是默认图片
const
defaultCover
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
;
const
isDefaultCover
=
coverUrl
===
defaultCover
;
const
[
assignorModalVisible
,
setAssignorModalVisible
]
=
useState
(
false
);
// 指派学员弹窗显隐
const
[
collaboratorModalVisible
,
setCollaboratorModalVisible
]
=
useState
(
false
);
// 协同者弹窗显隐
// 使用默认封面图
function
handleResetCoverUrl
()
{
message
.
success
(
'已替换为默认图'
);
props
.
onChange
(
'coverUrl'
,
{
fileUrl
:
defaultCover
});
}
// 从云盘选择封面
function
handleSelectCover
(
file
)
{
if
(
file
){
setImgClipVisible
(
true
);
setImageFile
(
file
);
}
else
{
message
.
warning
(
'请选择文件!'
)
}
}
function
getSignature
(
blob
,
fileName
)
{
Upload
.
uploadBlobToOSS
(
blob
,
'cover'
+
new
Date
().
valueOf
(),
null
,
'signInfo'
).
then
((
signInfo
)
=>
{
const
{
fileUrl
,
resourceId
}
=
signInfo
;
setImgClipVisible
(
false
);
setShowSelectFileModal
(
false
);
props
.
onChange
(
'coverUrl'
,
{
fileUrl
,
resourceId
});
});
}
// 禁选日期
function
disabledDate
(
current
)
{
return
current
&&
current
<
moment
().
startOf
(
'day'
);
}
// 禁选时间
function
disabledRangeTime
(
date
,
type
)
{
if
(
moment
(
date
).
isSame
(
moment
(),
'day'
))
{
return
{
disabledHours
:
()
=>
{
const
hours
=
[];
for
(
let
i
=
0
;
i
<
moment
().
hour
();
i
++
)
{
hours
.
push
(
i
);
}
return
hours
;
},
disabledMinutes
:
()
=>
{
const
currentMinute
=
moment
().
minute
();
const
currentHour
=
moment
(
date
).
hour
();
const
minutes
=
[];
if
(
currentHour
===
moment
().
hour
())
{
for
(
let
i
=
0
;
i
<
currentMinute
;
i
++
)
{
minutes
.
push
(
i
);
}
}
return
minutes
;
},
};
}
return
{
disabledHours
:
()
=>
[],
disabledMinutes
:
()
=>
[],
disabledSeconds
:
()
=>
[],
};
}
function
confirmAddCollaborator
(
data
)
{
props
.
onChange
(
'helpStoreUserIds'
,
data
);
}
function
confirmAddAssignor
(
data
)
{
props
.
onChange
(
'assignList'
,
data
);
setAssignorModalVisible
(
false
);
}
function
removeSelectedCollaborator
(
tag
)
{
const
_helpStoreUserIds
=
helpStoreUserIds
.
filter
((
item
)
=>
item
.
checkedId
!==
tag
.
checkedId
);
props
.
onChange
(
'helpStoreUserIds'
,
_helpStoreUserIds
);
}
function
removeCheckedAssignor
(
tag
)
{
const
_assignList
=
assignList
.
filter
((
item
)
=>
item
.
checkedId
!==
tag
.
checkedId
);
props
.
onChange
(
'assignList'
,
_assignList
);
}
function
checkTime
()
{
if
(
!
startTime
&&
!
endTime
)
{
return
'请选择培训时间'
;
}
if
(
!
startTime
)
{
return
'请选择开始时间'
;
}
if
(
!
endTime
)
{
return
'请选择结束时间'
;
}
if
((
type
===
'add'
||
taskState
===
'UN_START'
)
&&
startTime
<
new
Date
().
getTime
())
{
return
'开始时间不能早于现在'
;
}
if
(
!
endTime
>
new
Date
().
getTime
())
{
return
'结束时间不能早于现在'
;
}
return
false
;
}
return
(
<
div
className=
'basic-info__form'
>
<
Form
>
<
FormItem
label=
'培训任务名称'
required
validateStatus=
{
startCheck
&&
(
!
taskName
||
taskName
.
length
>
20
)
?
'error'
:
''
}
help=
{
startCheck
&&
((
!
taskName
&&
'请输入培训任务名称'
)
||
(
taskName
.
length
>
20
&&
'任务名称最多20字'
))
}
>
<
Input
value=
{
taskName
}
placeholder=
'请输入培训任务名称(20字以内)'
maxLength=
{
20
}
style=
{
{
width
:
300
}
}
onChange=
{
(
e
)
=>
props
.
onChange
(
'taskName'
,
e
.
target
.
value
)
}
/>
</
FormItem
>
<
FormItem
label=
'封面图'
>
<
div
className=
'cover__wrap'
>
<
div
className=
'opt-box'
>
<
Button
onClick=
{
()
=>
{
setShowSelectFileModal
(
true
);
}
}
>
上传封面
</
Button
>
<
span
className=
{
`default-btn ${isDefaultCover ? 'disabled' : ''}`
}
onClick=
{
handleResetCoverUrl
}
>
使用默认图
</
span
>
<
div
className=
'tips'
>
建议尺寸1280*720px或16:9。封面图最大5M,支持jpg、jpeg和png。
</
div
>
</
div
>
<
div
className=
'img-box'
>
{
isDefaultCover
&&
<
span
className=
'default-tag'
>
默认图
</
span
>
}
<
img
src=
{
coverUrl
}
alt=
''
/>
</
div
>
</
div
>
</
FormItem
>
<
FormItem
label=
'培训时间'
>
<
div
className=
'duration__wrap'
>
<
Radio
.
Group
value=
{
timeType
}
disabled=
{
originTimeType
===
'VALIDITY'
&&
taskState
===
'STARTING'
}
onChange=
{
(
e
)
=>
{
props
.
onChange
(
'timeType'
,
e
.
target
.
value
);
}
}
>
<
Space
direction=
'vertical'
size=
{
16
}
>
<
Radio
value=
'FOREVER'
>
永久有效
<
span
className=
'tips'
>
设置为“永久有效”,发布后任务开始生效,取消发布后失效
</
span
>
</
Radio
>
<
Radio
value=
'VALIDITY'
>
固定时间段
{
timeType
===
'VALIDITY'
&&
(
<
div
className=
'picker-box'
>
<
FormItem
validateStatus=
{
startCheck
&&
checkTime
()
?
'error'
:
''
}
help=
{
startCheck
&&
checkTime
()
}
>
<
RangePicker
style=
{
{
width
:
320
}
}
showTime=
{
{
defaultValue
:
[
moment
().
add
(
10
,
'minutes'
),
moment
().
add
(
10
,
'minutes'
)]
}
}
ranges=
{
{
近
7
天
:
[
type
===
'edit'
&&
taskState
===
'STARTING'
?
moment
(
startTime
)
:
moment
().
add
(
10
,
'minute'
),
moment
().
add
(
6
,
'day'
).
endOf
(
'day'
),
],
近
1
个月
:
[
type
===
'edit'
&&
taskState
===
'STARTING'
?
moment
(
startTime
)
:
moment
().
add
(
10
,
'minute'
),
moment
().
add
(
1
,
'month'
).
endOf
(
'day'
),
],
近
3
个月
:
[
type
===
'edit'
&&
taskState
===
'STARTING'
?
moment
(
startTime
)
:
moment
().
add
(
10
,
'minute'
),
moment
().
add
(
3
,
'month'
).
endOf
(
'day'
),
],
}
}
disabledDate=
{
disabledDate
}
disabledTime=
{
disabledRangeTime
}
disabled=
{
[
type
===
'edit'
&&
taskState
===
'STARTING'
,
false
]
}
value=
{
[
startTime
?
moment
(
Number
(
startTime
))
:
null
,
endTime
?
moment
(
Number
(
endTime
))
:
null
]
}
format=
'YYYY-MM-DD HH:mm'
onChange=
{
(
date
)
=>
{
props
.
onChange
(
'trainDate'
,
date
);
}
}
/>
{
' '
}
</
FormItem
>
</
div
>
)
}
</
Radio
>
</
Space
>
</
Radio
.
Group
>
</
div
>
</
FormItem
>
<
FormItem
label=
'学习模式'
required
extra=
{
<
div
className=
'learning-model-tips'
>
提示:任务开始后学习模式将不允许更换
</
div
>
}
>
<
div
className=
'learning-model__wrap'
>
<
Radio
.
Group
value=
{
learnType
}
disabled=
{
taskState
===
'STARTING'
}
onChange=
{
(
e
)
=>
props
.
onChange
(
'learnType'
,
e
.
target
.
value
)
}
>
<
Space
direction=
'vertical'
size=
{
16
}
>
<
Radio
value=
'FREEDOM'
>
自由学习
</
Radio
>
<
Radio
value=
'ORDER'
>
闯关学习
<
Tooltip
title=
'学员必须按顺序学习'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
,
}
}
>

</
i
>
</
Tooltip
>
</
Radio
>
</
Space
>
</
Radio
.
Group
>
</
div
>
</
FormItem
>
<
FormItem
label=
{
<
span
>
指派学员
<
Tooltip
title=
'选择需要培训的人员'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
,
}
}
>

</
i
>
</
Tooltip
>
</
span
>
}
required
validateStatus=
{
startCheck
&&
assignList
.
length
===
0
?
'error'
:
''
}
help=
{
startCheck
&&
assignList
.
length
===
0
&&
'请选择指派学员'
}
>
<
Button
style=
{
{
display
:
'block'
}
}
onClick=
{
()
=>
{
setAssignorModalVisible
(
true
);
}
}
>
添加指派学员
</
Button
>
{
assignList
.
length
>
0
&&
(
<
Space
size=
{
'12'
}
direction=
{
'vertical'
}
className=
'select-obj'
>
{
depAssignList
.
length
>
0
&&
(
<
div
className=
'obj-type-container'
>
<
div
className=
'type-title'
>
已选组织:
</
div
>
<
div
className=
'tag-box'
>
{
_
.
map
(
depAssignList
,
(
tag
)
=>
{
return
(
<
Tag
key=
{
tag
.
checkedId
}
closeIcon=
{
<
span
className=
'icon iconfont close-icon'
>

</
span
>
}
onClose=
{
()
=>
removeCheckedAssignor
(
tag
)
}
closable
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
tag
.
checkedName
}
/>
</
Tag
>
);
})
}
</
div
>
</
div
>
)
}
{
userAssignList
.
length
>
0
&&
(
<
div
className=
'obj-type-container'
>
<
div
className=
'type-title'
>
已选学员:
</
div
>
<
div
className=
'tag-box'
>
{
_
.
map
(
userAssignList
,
(
tag
)
=>
{
return
(
<
Tag
key=
{
tag
.
checkedId
}
closeIcon=
{
<
span
className=
'icon iconfont close-icon'
>

</
span
>
}
onClose=
{
()
=>
removeCheckedAssignor
(
tag
)
}
closable
>
<
WWOpenDataCom
type=
'userName'
openid=
{
tag
.
checkedName
}
/>
</
Tag
>
);
})
}
</
div
>
</
div
>
)
}
</
Space
>
)
}
</
FormItem
>
<
FormItem
label=
{
<
span
>
协同人员
<
Tooltip
title=
'选择员工协同完成任务指派和督学工作'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
,
}
}
>

</
i
>
</
Tooltip
>
</
span
>
}
>
<
Button
style=
{
{
display
:
'block'
}
}
onClick=
{
()
=>
{
setCollaboratorModalVisible
(
true
);
}
}
>
添加协同者
</
Button
>
{
helpStoreUserIds
.
length
>
0
&&
(
<
div
className=
'select-obj'
>
{
_
.
map
(
helpStoreUserIds
,
(
tag
)
=>
{
return
(
<
Tag
key=
{
tag
.
checkedId
}
closeIcon=
{
<
span
className=
'icon iconfont close-icon'
>

</
span
>
}
className=
{
tag
.
checkedId
===
createId
&&
'disabled'
}
onClose=
{
()
=>
removeSelectedCollaborator
(
tag
)
}
closable
>
<
WWOpenDataCom
type=
'userName'
openid=
{
tag
.
checkedName
}
/>
</
Tag
>
);
})
}
</
div
>
)
}
</
FormItem
>
<
FormItem
label=
'培训目的'
>
{
(
type
===
'add'
||
loadintroduce
)
&&
(
<
GraphicsEditor
maxLimit=
{
1000
}
id=
'intro'
isIntro=
{
true
}
placeholder=
'请输入培训目的'
detail=
{
{
content
:
introduce
,
}
}
onChange=
{
(
val
)
=>
{
props
.
onChange
(
'introduce'
,
val
);
}
}
/>
)
}
</
FormItem
>
</
Form
>
{
showSelectFileModal
&&
(
<
SelectPrepareFileModal
key=
'basic'
operateType=
'select'
multiple=
{
false
}
accept=
'image/jpeg,image/png,image/jpg'
selectTypeList=
{
[
'JPG'
,
'JPEG'
,
'PNG'
]
}
tooltip=
'支持文件类型:jpg、jpeg、png'
isOpen=
{
showSelectFileModal
}
onClose=
{
()
=>
{
setShowSelectFileModal
(
false
);
}
}
onSelect=
{
handleSelectCover
}
/>
)
}
{
imgClipVisible
&&
(
<
ImgClipModal
visible=
{
imgClipVisible
}
imgUrl=
{
imageFile
.
ossUrl
}
onConfirm=
{
getSignature
}
onClose=
{
()
=>
{
setImgClipVisible
(
false
);
}
}
/>
)
}
{
assignorModalVisible
&&
(
<
ChooseAssignorModal
currentAssignorList=
{
assignList
}
visible=
{
assignorModalVisible
}
onClose=
{
()
=>
{
setAssignorModalVisible
(
false
);
}
}
onConfirm=
{
(
data
)
=>
{
confirmAddAssignor
(
data
);
}
}
/>
)
}
{
collaboratorModalVisible
&&
(
<
ChooseCollaboratorModal
createId=
{
createId
}
currentCollaboratorList=
{
helpStoreUserIds
}
visible=
{
collaboratorModalVisible
}
onClose=
{
()
=>
{
setCollaboratorModalVisible
(
false
);
}
}
onConfirm=
{
(
data
)
=>
{
confirmAddCollaborator
(
data
);
}
}
/>
)
}
</
div
>
);
}
export
default
BasicInfo
;
src/modules/task-center/train-task/components/BasicInfo.less
0 → 100644
View file @
b427be83
.basic-info__form {
margin-bottom: 138px;
.cover {
display: flex;
margin-top: 24px;
&__wrap {
position: relative;
.img-box {
position: relative;
margin-top: 8px;
width: 300px;
height: 170px;
.default-tag {
border-radius: 2px;
background: #d6d6d6;
font-size: 12px;
height: 18px;
width: 52px;
text-align: center;
color: #fff;
position: absolute;
top: 8px;
left: 8px;
}
img {
width: 100%;
height: 100%;
object-fit: contain;
}
}
.opt-box {
.default-btn {
margin-left: 12px;
color: #2966ff;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
pointer-events: none;
}
}
.tips {
margin-top: 8px;
font-size: 14px;
color: #999;
}
}
}
}
.duration {
&__wrap {
.tips {
color: #999999;
display: inline-block;
margin-left: 16px;
}
.picker-box {
display: inline-block;
margin-left: 16px;
.ant-form-item {
margin-bottom: 0 !important;
}
}
}
}
.select-obj {
width: 600px;
max-height: 90px;
overflow-y: scroll;
padding: 12px;
border-radius: 4px;
margin-top: 10px;
border: 1px solid #e8e8e8;
color: #666666;
.obj-type-container {
display: flex;
overflow-wrap: normal;
.type-title {
width: 70px;
flex-shrink: 0;
}
}
.close-icon {
font-size: 14px;
color: #cccccc;
}
.disabled {
color: #ccc !important;
cursor: not-allowed !important;
pointer-events: none !important;
}
}
.learning-model-tips {
margin-top: 8px;
color: #999999;
line-height: 20px;
}
.ant-form-item {
margin-bottom: 24px !important;
.ant-form-item-label > label {
width: 108px;
justify-content: flex-end;
}
&:not(:first-child) .ant-form-item-label > label {
height: 22px !important;
}
.ant-form-item-control-input {
min-height: 22px !important;
}
.ant-tag {
border: 1px solid #cccccc;
color: #666666;
margin-bottom: 10px;
font-size: 14px;
}
}
}
src/modules/task-center/train-task/components/ExpiredCourseList.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-03 10:47:59
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 22:04:31
* @Description: 编辑培训任务-失效课程
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
List
,
message
,
Modal
}
from
'antd'
;
import
'./ExpiredCourseList.less'
;
import
ENUM
from
'../../enum'
;
import
moment
from
'moment'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
function
ExpiredCourseList
(
props
)
{
const
[
expiredCourseList
,
setExpiredCourseList
]
=
useState
([]);
// 失效课程
useEffect
(()
=>
{
getTrainingCourseAutoCancel
();
},
[]);
// 获取培训任务失效的课程
function
getTrainingCourseAutoCancel
()
{
TaskCenterService
.
getTrainingCourseAutoCancel
({
taskId
:
props
.
taskId
}).
then
((
res
)
=>
{
setExpiredCourseList
(
res
.
result
);
});
}
// 移除未成功开课课程
function
deLExpiredCourse
(
contentId
)
{
const
{
taskId
}
=
props
;
Modal
.
confirm
({
content
:
'你确定要删除该数据内容吗?'
,
okText
:
'确定'
,
cancelText
:
'取消'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
onOk
:
()
=>
{
const
params
=
{
taskId
,
contentIdList
:
[
contentId
],
};
TaskCenterService
.
delTaskCancelContent
(
params
).
then
((
res
)
=>
{
message
.
success
(
'删除成功'
);
getTrainingCourseAutoCancel
();
});
},
});
}
return
(
<
div
>
{
expiredCourseList
.
length
>
0
&&
(
<
div
className=
'expired-list-page'
>
<
div
className=
'tip'
>
为了不影响学员学习,「未成功开课」的课程已从任务中移出,具体课程如下所示:
</
div
>
<
List
dataSource=
{
expiredCourseList
}
renderItem=
{
(
item
)
=>
(
<
List
.
Item
>
<
div
className=
'item-detail'
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'content-status'
>
未成功开课
</
span
>
<
span
className=
'stage-name'
>
{
item
.
stageName
}
</
span
>
<
span
className=
'content-name'
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
item
.
courseType
]
}
/>
<
span
>
{
item
.
courseName
}
</
span
>
</
span
>
<
span
className=
'teacher-name'
>
{
item
.
teacherName
}
</
span
>
<
span
className=
'split'
>
|
</
span
>
<
span
className=
'course-time'
>
{
moment
(
item
.
startTime
).
format
(
'YYYY-MM-DD HH:mm'
)
}
~
{
moment
(
item
.
endTime
).
format
(
'HH:mm'
)
}
</
span
>
<
span
className=
'del-btn'
onClick=
{
()
=>
{
deLExpiredCourse
(
item
.
courseId
);
}
}
>
删除记录
</
span
>
</
div
>
</
List
.
Item
>
)
}
/>
</
div
>
)
}
</
div
>
);
}
export
default
ExpiredCourseList
;
src/modules/task-center/train-task/components/ExpiredCourseList.less
0 → 100644
View file @
b427be83
.expired-list-page {
.tip {
color: #999999;
line-height: 20px;
margin-top: 8px;
margin-bottom: 16px;
}
.ant-list-item {
padding: 16px;
border: none !important;
&:nth-child(even) {
background: #ffffff;
}
&:nth-child(odd) {
background: #f7f8f9;
}
.item-detail {
display: inline-flex;
width: 100%;
height: 20px;
.icon {
font-size: 14px;
color: #ff4f4f;
margin-right: 4px;
}
.content-status {
color: #999999;
margin-right: 24px;
}
.stage-name {
color: #333333;
margin-right: 12px;
}
.content-name {
color: #333333;
margin-right: 12px;
vertical-align: middle;
> * {
vertical-align: middle;
}
img {
width: 20px;
height: 20px;
margin-right: 12px;
}
}
.teacher-name,
.course-time {
color: #999999;
}
.split {
margin-left: 12px;
margin-right: 12px;
color: #999999;
}
.del-btn {
margin-left: auto;
color: #2966ff;
cursor: pointer;
}
}
}
}
src/modules/task-center/train-task/components/RelatedCourseDrawer.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-01 17:28:30
* @LastEditors: yuananting
* @LastEditTime: 2021-08-16 19:53:06
* @Description: 新建培训任务-关联课程抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
Component
}
from
'react'
;
import
_
from
'underscore'
;
import
{
Radio
,
Tabs
,
Drawer
,
Input
,
message
,
Button
,
Tooltip
}
from
'antd'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
college
from
'@/common/lottie/college'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
User
from
'@/common/js/user'
;
import
Service
from
'@/common/js/service'
;
import
ENUM
from
'../../enum'
;
import
'./RelatedCourseDrawer.less'
;
const
{
Search
}
=
Input
;
const
{
TabPane
}
=
Tabs
;
class
RelatedCourseDrawer
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
// 直播课列表相关参数
liveDataSource
:
[],
liveSize
:
10
,
liveQuery
:
{
current
:
1
,
},
liveTotalCount
:
0
,
selectLive
:
[],
//弹窗内已选择的直播课程
currentLiveCourseListData
:
[],
//页面中已关联的直播课程
// 线上课列表相关参数(内外部课程)
videoCourseDivision
:
'internal'
,
videoDataSource
:
{
external
:
[],
internal
:
[],
},
videoSize
:
{
external
:
10
,
internal
:
10
,
},
videoSearchName
:
{
external
:
''
,
internal
:
''
,
},
videoSearchDefalt
:
''
,
videoQuery
:
{
external
:
{
current
:
1
,
},
internal
:
{
current
:
1
,
},
},
videoTotalCount
:
{
external
:
0
,
internal
:
0
,
},
selectVideo
:
{
external
:
[],
internal
:
[],
},
//弹窗内已选择的线上课程
currentVideoCourseListData
:
{
external
:
[],
internal
:
[],
},
//页面中已关联的线上课程
pictureDataSource
:
[],
pictureSize
:
10
,
pictureQuery
:
{
current
:
1
,
},
pictureTotalCount
:
0
,
selectPicture
:
[],
//弹窗内已选择的线上课程
currentPictureCourseListData
:
[],
//页面中已关联的线上课程
activeKey
:
'live'
,
currentTaskContentData
:
props
.
data
[
props
.
selectedStageIndex
].
contentList
||
[],
};
}
componentDidMount
()
{
this
.
handleFetchLiveDataList
();
this
.
handleFetchVideoDataList
();
this
.
handleFetchPictureDataList
();
}
// 获取直播课列表
handleFetchLiveDataList
=
()
=>
{
const
{
liveQuery
,
liveSize
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
let
currentLiveCourseListData
=
[];
_data
.
map
((
item
)
=>
{
item
.
contentList
.
map
((
childItem
,
childIndex
)
=>
{
if
(
childItem
.
courseType
===
'LIVE'
)
{
currentLiveCourseListData
.
push
(
childItem
.
contentId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
liveQuery
,
size
:
liveSize
,
excludeCourseIdList
:
currentLiveCourseListData
,
};
CourseService
.
getLiveCloudCourseBasePage
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
liveDataSource
:
records
,
liveTotalCount
:
Number
(
total
),
currentLiveCourseListData
,
});
});
};
// 获取线上课列表
handleFetchVideoDataList
=
()
=>
{
const
{
videoQuery
,
videoSize
,
videoDataSource
,
videoTotalCount
,
videoCourseDivision
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
console
.
log
(
'_data'
,
_data
);
let
currentVideoCourseListData
=
[];
_data
.
map
((
item
,
index
)
=>
{
item
.
contentList
.
map
((
childItem
,
childIndex
)
=>
{
console
.
log
(
'childItem'
,
childItem
);
if
(
childItem
.
courseType
===
'VOICE'
)
{
currentVideoCourseListData
.
push
(
childItem
.
contentId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
videoQuery
[
videoCourseDivision
],
size
:
videoSize
[
videoCourseDivision
],
courseDivision
:
videoCourseDivision
===
'internal'
?
'INTERNAL'
:
'EXTERNAL'
,
excludeCourseIdList
:
currentVideoCourseListData
,
};
CourseService
.
videoScheduleBasePage
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
videoDataSource
:
{
...
videoDataSource
,
[
videoCourseDivision
]:
records
,
},
videoTotalCount
:
{
...
videoTotalCount
,
[
videoCourseDivision
]:
Number
(
total
),
},
currentVideoCourseListData
,
});
});
};
// 获取图文课列表
handleFetchPictureDataList
=
()
=>
{
const
{
pictureQuery
,
pictureSize
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
let
currentPictureCourseListData
=
[];
_data
.
map
((
item
,
index
)
=>
{
item
.
contentList
.
map
((
childItem
,
childIndex
)
=>
{
if
(
childItem
.
courseType
===
'PICTURE'
)
{
currentPictureCourseListData
.
push
(
childItem
.
contentId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
pictureQuery
,
size
:
pictureSize
,
courseType
:
'PICTURE'
,
storeId
:
User
.
getStoreId
(),
excludeCourseIdList
:
currentPictureCourseListData
,
};
Service
.
Hades
(
'public/hades/mediaCoursePage'
,
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
pictureDataSource
:
records
,
pictureTotalCount
:
Number
(
total
),
currentPictureCourseListData
,
});
});
};
handleChangVideoCourseName
=
(
value
)
=>
{
const
{
videoQuery
,
videoCourseDivision
,
videoSearchName
}
=
this
.
state
;
videoQuery
[
videoCourseDivision
].
courseName
=
value
;
videoQuery
[
videoCourseDivision
].
current
=
1
;
this
.
setState
({
...
videoQuery
,
videoSearchDefalt
:
value
,
videoSearchName
:
{
...
videoSearchName
,
[
videoCourseDivision
]:
value
,
},
});
};
handleChangLiveCourseName
=
(
value
)
=>
{
const
{
liveQuery
}
=
this
.
state
;
liveQuery
.
courseName
=
value
;
liveQuery
.
current
=
1
;
this
.
setState
({
liveQuery
,
});
};
handleChangPictureCourseName
=
(
value
)
=>
{
const
{
pictureQuery
}
=
this
.
state
;
pictureQuery
.
courseName
=
value
;
pictureQuery
.
current
=
1
;
this
.
setState
({
pictureQuery
,
});
};
onShowLiveSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
liveSize
:
size
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
};
onShowVideoSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
videoSize
:
size
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
};
onShowPictureSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
pictureSize
:
size
,
},
()
=>
{
this
.
handleFetchPictureDataList
();
}
);
};
// 请求表头
parseCourseColumns
=
(
type
)
=>
{
const
columns
=
[
{
title
:
(
<
span
>
<
span
>
课程信息
</
span
>
<
Tooltip
title=
'仅显示未关联课程,已关联课程不支持重复选择'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'400'
}
}
>

</
i
>
</
Tooltip
>
</
span
>
),
key
:
'course'
,
dataIndex
:
'course'
,
width
:
'30%'
,
render
:
(
val
,
record
)
=>
{
if
(
type
===
'live'
)
{
let
hasCover
=
false
;
return
(
<
div
className=
'course-info'
>
{
record
.
courseMediaVOS
.
map
((
item
)
=>
{
if
(
item
.
contentType
===
'COVER'
)
{
hasCover
=
true
;
return
<
img
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>;
}
return
null
;
})
}
<
If
condition=
{
!
hasCover
}
>
<
img
className=
'course-cover'
src=
{
'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'
}
alt=
''
/>
</
If
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
div
>
);
}
else
{
const
{
coverUrl
}
=
record
;
return
(
<
div
className=
'course-info'
>
<
img
className=
'course-cover'
src=
{
coverUrl
||
(
type
===
'video'
?
'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png'
:
'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'
)
}
alt=
''
/>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
div
>
);
}
},
},
type
===
'live'
?
{
title
:
'课程状态'
,
key
:
'courseState'
,
dataIndex
:
'courseState'
,
width
:
'25%'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'course-state'
>
<
span
className=
'status-point'
style=
{
{
backgroundColor
:
ENUM
.
trainStatus
[
val
||
'UN_START'
].
color
}
}
></
span
>
<
span
>
{
ENUM
.
trainStatus
[
val
||
'UN_START'
].
text
}
</
span
>
</
div
>
);
},
}
:
{},
type
===
'live'
?
{
title
:
'上课时间'
,
key
:
'courseTime'
,
dataIndex
:
'courseTime'
,
width
:
'25%'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
>
<
div
>
{
formatDate
(
'YYYY-MM-DD'
,
record
.
startTime
)
}
</
div
>
<
div
>
{
formatDate
(
'H:i'
,
record
.
startTime
)
}
~
{
formatDate
(
'H:i'
,
record
.
endTime
)
}
</
div
>
</
div
>
);
},
}
:
type
===
'video'
?
{
title
:
'课节数'
,
key
:
'courseChapterNum'
,
dataIndex
:
'courseChapterNum'
,
width
:
'20%'
,
render
:
(
val
,
record
)
=>
{
return
<
span
>
{
val
||
1
}
</
span
>;
},
}
:
{
title
:
'更新时间'
,
key
:
'updated'
,
dataIndex
:
'updated'
,
width
:
'25%'
,
render
:
(
val
,
record
)
=>
{
return
<
span
className=
'course-status'
>
{
formatDate
(
'YYYY-MM-DD'
,
record
.
updated
)
}
</
span
>;
},
},
{
title
:
'学院展示'
,
key
:
'shelfState'
,
dataIndex
:
'shelfState'
,
width
:
'20%'
,
render
:
(
val
,
record
)
=>
{
return
<
span
>
{
record
.
shelfState
===
'YES'
?
'开启'
:
'关闭'
}
</
span
>;
},
},
];
return
columns
;
};
selectLiveList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskContentData
,
selectLive
,
selectPicture
}
=
this
.
state
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectLive
,
(
item
)
=>
item
.
liveCourseId
===
record
.
liveCourseId
))
{
_list
=
_
.
uniq
(
selectLive
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
liveCourseId
);
}
else
{
_list
=
_
.
reject
(
selectLive
,
(
item
)
=>
item
.
liveCourseId
===
record
.
liveCourseId
);
}
if
(
_list
.
length
+
currentTaskContentData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectLive
:
_list
});
};
selectVideoList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskContentData
,
selectLive
,
selectPicture
,
videoCourseDivision
}
=
this
.
state
;
let
{
[
videoCourseDivision
]:
selectList
}
=
selectVideo
;
let
otherVideoCourseDivision
=
videoCourseDivision
===
'internal'
?
'external'
:
'internal'
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectList
,
(
item
)
=>
item
.
id
===
record
.
id
))
{
_list
=
_
.
uniq
(
selectList
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectList
,
(
item
)
=>
item
.
id
===
record
.
id
);
}
if
(
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskContentData
.
length
+
selectLive
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectVideo
:
{
...
selectVideo
,
[
videoCourseDivision
]:
_list
,
},
});
};
selectPictureList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskContentData
,
selectLive
,
selectPicture
}
=
this
.
state
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectPicture
,
(
item
)
=>
item
.
id
===
record
.
id
))
{
_list
=
_
.
uniq
(
selectPicture
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectPicture
,
(
item
)
=>
item
.
id
===
record
.
id
);
}
if
(
_list
.
length
+
currentTaskContentData
.
length
+
selectLive
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectPicture
:
_list
});
};
clearSelectCourse
=
()
=>
{
this
.
setState
({
selectLive
:
[],
selectVideo
:
{
internal
:
[],
external
:
[],
},
selectPicture
:
[],
});
};
handleSelectVideo
=
(
selectVideo
)
=>
{
return
selectVideo
.
map
((
item
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
id
;
_item
.
courseType
=
'VOICE'
;
_item
.
courseName
=
item
.
courseName
;
_item
.
courseChapterNum
=
item
.
courseChapterNum
;
return
_item
;
});
};
handleSelectLive
=
(
selectLive
)
=>
{
return
selectLive
.
map
((
item
,
index
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
liveCourseId
;
_item
.
courseType
=
'LIVE'
;
_item
.
courseName
=
item
.
courseName
;
_item
.
courseState
=
item
.
courseState
;
return
_item
;
});
};
videoCourseDivisionChange
=
(
e
)
=>
{
const
{
videoSearchName
}
=
this
.
state
;
this
.
setState
(
{
videoCourseDivision
:
e
.
target
.
value
,
videoSearchDefalt
:
videoSearchName
[
e
.
target
.
value
],
},
()
=>
{
this
.
handleFetchVideoDataList
();
}
);
};
handleSelectPicture
=
(
selectPicture
)
=>
{
return
selectPicture
.
map
((
item
,
index
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
id
;
_item
.
courseType
=
'PICTURE'
;
_item
.
courseName
=
item
.
courseName
;
return
_item
;
});
};
renderTipFooter
=
()
=>
{
const
{
activeKey
}
=
this
.
state
;
let
href
=
''
;
switch
(
activeKey
)
{
case
'live'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-live-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的直播课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
case
'video'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-video-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的线上课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
case
'picture'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-graphics-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的图文课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
default
:
break
;
}
return
href
;
};
render
()
{
const
{
liveDataSource
,
liveSize
,
liveQuery
,
liveTotalCount
,
selectLive
,
videoDataSource
,
videoSize
,
videoQuery
,
videoSearchDefalt
,
videoTotalCount
,
selectVideo
,
currentTaskContentData
,
selectPicture
,
pictureDataSource
,
pictureSize
,
pictureQuery
,
pictureTotalCount
,
videoCourseDivision
,
activeKey
,
}
=
this
.
state
;
return
(
<
Drawer
title=
'关联课程'
width=
{
720
}
maskClosable=
{
false
}
closable=
{
true
}
onClose=
{
this
.
props
.
onClose
}
visible=
{
true
}
mask
className=
'related-course-drawer'
>
<
div
>
<
Tabs
type=
'line'
defaultActiveKey=
'live'
onChange=
{
(
activeKey
)
=>
{
this
.
setState
({
activeKey
:
activeKey
});
}
}
>
<
TabPane
tab=
'直播课'
key=
'live'
>
<
div
className=
'search-container'
>
<
Search
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangLiveCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchLiveDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskContentData
.
length
}
个课程,可继续选择
{
20
-
currentTaskContentData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
liveCourseId
}
dataSource=
{
liveDataSource
}
columns=
{
this
.
parseCourseColumns
(
'live'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectLive
,
'liveCourseId'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectLiveList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
if
(
selected
)
{
_list
=
_
.
uniq
(
selectLive
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
liveCourseId
);
}
else
{
_list
=
_
.
reject
(
selectLive
,
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
liveCourseId
===
item
.
liveCourseId
));
}
if
(
_list
.
length
+
currentTaskContentData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
currentTaskContentData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
+
selectPicture
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectLive
:
_list
});
},
}
}
/>
{
liveDataSource
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
liveQuery
.
current
-
1
}
pageSize=
{
liveSize
}
size=
'small'
total=
{
liveTotalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
liveQuery
,
current
:
page
+
1
};
this
.
setState
(
{
liveQuery
:
_query
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowLiveSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
<
TabPane
tab=
'线上课'
key=
'video'
>
<
Radio
.
Group
value=
{
videoCourseDivision
}
onChange=
{
this
.
videoCourseDivisionChange
}
style=
{
{
marginBottom
:
16
}
}
>
<
Radio
.
Button
value=
'internal'
>
内部课程
</
Radio
.
Button
>
<
Radio
.
Button
value=
'external'
>
外部课程
</
Radio
.
Button
>
</
Radio
.
Group
>
<
div
className=
'search-container'
>
<
Search
value=
{
videoSearchDefalt
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangVideoCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchVideoDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskContentData
.
length
}
个课程,可继续选择
{
20
-
currentTaskContentData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
videoDataSource
[
videoCourseDivision
]
}
columns=
{
this
.
parseCourseColumns
(
'video'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectVideo
[
videoCourseDivision
],
'id'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectVideoList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
let
otherVideoCourseDivision
=
videoCourseDivision
===
'internal'
?
'external'
:
'internal'
;
if
(
selected
)
{
_list
=
_
.
uniq
(
selectVideo
[
videoCourseDivision
].
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectVideo
[
videoCourseDivision
],
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
));
}
if
(
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskContentData
.
length
+
selectLive
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskContentData
.
length
+
selectLive
.
length
+
selectPicture
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectVideo
:
{
...
selectVideo
,
[
videoCourseDivision
]:
_list
,
},
});
},
}
}
/>
{
videoDataSource
[
videoCourseDivision
].
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
videoQuery
[
videoCourseDivision
].
current
-
1
}
pageSize=
{
videoSize
[
videoCourseDivision
]
}
size=
'small'
total=
{
videoTotalCount
[
videoCourseDivision
]
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
videoQuery
[
videoCourseDivision
],
current
:
page
+
1
};
this
.
setState
(
{
videoQuery
:
{
...
videoQuery
,
[
videoCourseDivision
]:
_query
,
},
},
()
=>
{
this
.
handleFetchVideoDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowVideoSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
<
TabPane
tab=
'图文课'
key=
'picture'
>
<
div
className=
'search-container'
>
<
Search
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangPictureCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchPictureDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskContentData
.
length
}
个课程,可继续选择
{
20
-
currentTaskContentData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
pictureDataSource
}
columns=
{
this
.
parseCourseColumns
(
'picture'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectPicture
,
'id'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectPictureList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
if
(
selected
)
{
_list
=
_
.
uniq
(
selectPicture
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectPicture
,
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
));
}
if
(
_list
.
length
+
currentTaskContentData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
currentTaskContentData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectPicture
:
_list
});
},
}
}
/>
{
pictureDataSource
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
pictureQuery
.
current
-
1
}
pageSize=
{
pictureSize
}
size=
'small'
total=
{
pictureTotalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
pictureQuery
,
current
:
page
+
1
};
this
.
setState
(
{
pictureQuery
:
_query
,
},
()
=>
{
this
.
handleFetchPictureDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowPictureSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
</
Tabs
>
</
div
>
<
div
className=
'footer shrink-footer'
>
{
!
(
activeKey
===
'video'
&&
videoCourseDivision
===
'external'
)
&&
this
.
renderTipFooter
()
}
<
Button
onClick=
{
this
.
props
.
onClose
}
>
取消
</
Button
>
<
Button
type=
'primary'
onClick=
{
()
=>
this
.
props
.
onSelect
([
...
this
.
handleSelectVideo
(
selectVideo
.
internal
),
...
this
.
handleSelectVideo
(
selectVideo
.
external
),
...
this
.
handleSelectLive
(
selectLive
),
...
this
.
handleSelectPicture
(
selectPicture
),
])
}
>
确定
</
Button
>
</
div
>
</
Drawer
>
);
}
}
export
default
RelatedCourseDrawer
;
src/modules/task-center/train-task/components/RelatedCourseDrawer.less
0 → 100644
View file @
b427be83
.related-course-drawer {
.link-create-course {
color: #666666;
font-size: 14px;
width: 638px;
text-align: left;
display: inline-block;
span {
color: #2966ff;
}
}
.search-container {
margin-bottom: 16px;
}
.select-area {
margin-bottom: 12px;
display: flex;
justify-content: space-between;
.select-box {
display: inline-box;
width: 186px;
background: #e9efff;
border-radius: 4px;
padding: 6px 16px;
margin-right: 8px;
display: flex;
justify-content: space-between;
.tip-icon {
color: #2966ff;
font-size: 14px;
margin-right: 4px;
}
.select-num {
color: #666666;
font-size: 14px;
}
.clear-btn {
text-align: right;
color: #5289fa;
font-size: 14px;
}
}
.related-box {
padding: 6px 16px;
background: #e9efff;
border-radius: 4px;
flex: 1;
color: #666666;
font-size: 14px;
}
}
.course-info {
display: flex;
align-items: center;
.course-cover {
width: 97px;
height: 55px;
display: inline-block;
border-radius: 4px;
margin-right: 8px;
}
.course-name {
font-size: 14px;
color: #666;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
width: 140px;
}
}
.course-state {
* {
vertical-align: middle;
display: inline-block;
}
.status-point {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 4px;
}
}
.footer {
position: fixed;
right: 0;
bottom: 0;
width: 720px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 16px 24px;
background: #fff;
border-top: 1px solid #e8e8e8;
z-index: 9999;
.ant-btn {
margin-left: 8px;
}
}
}
src/modules/task-center/train-task/components/RelatedExamDrawer.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-03 17:05:32
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 17:25:30
* @Description: 新建培训任务-关联考试抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'react'
;
import
{
Drawer
,
Form
,
Input
,
Button
,
Tooltip
,
Switch
,
Radio
,
InputNumber
,
message
}
from
'antd'
;
import
GraphicsEditor
from
'@/modules/course-manage/components/GraphicsEditor'
;
import
moment
from
'moment'
;
import
'./RelatedExamDrawer.less'
;
import
SelectPaperModal
from
'@/modules/teach-tool/examination-manager/SelectPaperModal'
;
import
User
from
'@/common/js/user'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
import
Bus
from
'@/core/bus'
;
function
RelatedExamDrawer
(
props
)
{
const
[
showPaperModal
,
setShowPaperModal
]
=
useState
(
false
);
const
[
paperInfo
,
setPaperInfo
]
=
useState
({});
const
[
answerAnalysis
,
setAnswerAnalysis
]
=
useState
(
'RIGHT_OR_WRONG'
);
// 答案与解析-默认仅显示对错
const
[
examDesc
,
setExamDesc
]
=
useState
(
''
);
// 考试说明
const
[
examDuration
,
setExamDuration
]
=
useState
(
null
);
// 考试时长
const
[
examName
,
setExamName
]
=
useState
(
''
);
// 考试名称
const
[
needOptionDisorder
,
setNeedOptionDisorder
]
=
useState
(
'OPTION_SORT'
);
// 选项乱序-默认正常顺序
const
[
paperId
,
setPaperId
]
=
useState
(
null
);
// 选择的试卷id
const
[
passRate
,
setPassRate
]
=
useState
(
0
);
// 及格比例
const
[
passScore
,
setPassScore
]
=
useState
(
60
);
// 及格分数
const
[
resultContent
,
setResultContent
]
=
useState
(
'PASS_AND_SCORE'
);
// 考试结果内容
const
[
resultShow
,
setResultShow
]
=
useState
(
'IMMEDIATELY'
);
// 考试结果查看-卷后立即显示考试结果
const
[
editorTextLength
,
setEditorTextLength
]
=
useState
(
0
);
// 考试说明长度
const
[
check
,
setCheck
]
=
useState
(
false
);
const
[
examTotal
,
setExamTotal
]
=
useState
(
0
);
const
[
samePaper
,
setSamePaper
]
=
useState
(
false
);
const
request
=
useRef
(
false
);
useEffect
(()
=>
{
Bus
.
bind
(
'editorLimit'
,
(
editorTextLength
)
=>
{
setEditorTextLength
(
editorTextLength
);
});
},
[]);
useEffect
(()
=>
{
setPaperId
(
paperInfo
.
paperId
);
setPassRate
(
paperInfo
.
passRate
);
setExamName
(
paperInfo
.
paperName
);
},
[
paperInfo
.
paperId
]);
useEffect
(()
=>
{
setPassScore
(
Math
.
round
(((
paperInfo
.
totalScore
||
0
)
*
(
passRate
||
0
))
/
100
));
setExamTotal
(
paperInfo
.
singleChoiceCnt
+
paperInfo
.
multiChoiceCnt
+
paperInfo
.
judgeCnt
+
paperInfo
.
gapFillingCnt
+
paperInfo
.
indefiniteChoiceCnt
||
0
);
},
[
paperInfo
.
paperId
,
passRate
]);
function
handleSave
()
{
if
(
request
.
current
)
{
return
;
}
setCheck
(
true
);
const
params
=
{
paperId
,
examName
,
passRate
,
examDuration
:
(
examDuration
||
0
)
*
60
*
1000
,
examDesc
,
needOptionDisorder
,
resultShow
,
resultContent
,
answerAnalysis
,
examEndTime
:
props
.
basicInfo
.
endTime
||
null
,
examStartTime
:
props
.
basicInfo
.
startTime
||
new
Date
().
valueOf
(),
passScore
,
source
:
0
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
};
console
.
log
(
'新建入参==============>'
,
params
);
if
(
!
paperId
||
samePaper
||
!
examName
||
examName
.
length
>
40
||
!
passRate
||
!
examDuration
||
editorTextLength
>
1000
||
(
props
.
basicInfo
.
timeType
===
'VALIDITY'
&&
props
.
basicInfo
.
startTime
&&
props
.
basicInfo
.
endTime
&&
props
.
basicInfo
.
startTime
+
examDuration
*
60
*
1000
>
props
.
basicInfo
.
endTime
)
)
{
return
;
}
request
.
current
=
true
;
setTimeout
(()
=>
{
request
.
current
=
false
;
},
2000
);
TaskCenterService
.
createTrainingExam
(
params
).
then
((
res
)
=>
{
props
.
onSave
(
res
.
result
);
});
}
return
(
<
Drawer
title=
'添加考试'
width=
{
720
}
maskClosable=
{
false
}
closable=
{
true
}
onClose=
{
props
.
onClose
}
visible=
{
true
}
mask
className=
'related-exam-drawer'
>
<
Form
labelCol=
{
{
span
:
4
}
}
wrapperCol=
{
{
span
:
20
}
}
layout=
'horizontal'
>
<
div
className=
'module-title'
>
基本信息
</
div
>
<
Form
.
Item
label=
'选择试卷'
validateStatus=
{
(
check
&&
!
paperId
)
||
samePaper
?
'error'
:
''
}
help=
{
(
check
&&
!
paperId
&&
'请选择试卷'
)
||
(
samePaper
&&
'已存在相同试卷'
)
}
required
>
<
Button
onClick=
{
()
=>
{
setShowPaperModal
(
true
);
}
}
>
{
paperInfo
.
paperId
?
'重新选择'
:
'选择试卷'
}
</
Button
>
{
paperInfo
.
paperId
&&
(
<
div
className=
'paper-title'
>
<
img
src=
'https://image.xiaomaiketang.com/xm/pY5imEhjzw.png'
alt=
''
/>
{
paperInfo
.
paperName
}
</
div
>
)
}
{
paperInfo
.
paperId
&&
(
<
div
className=
'paper-table'
>
<
div
className=
'header'
>
<
div
className=
'item'
>
单选题
</
div
>
<
div
className=
'item'
>
多选题
</
div
>
<
div
className=
'item'
>
判断题
</
div
>
<
div
className=
'item'
>
填空题
</
div
>
<
div
className=
'item long'
>
不定项选择题
</
div
>
<
div
className=
'item'
>
合计
</
div
>
</
div
>
<
div
className=
'body-list'
style=
{
{
borderBottom
:
'1px solid #e8e8e8'
}
}
>
<
div
className=
'item'
>
{
paperInfo
.
singleChoiceCnt
||
0
}
题
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
multiChoiceCnt
||
0
}
题
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
judgeCnt
||
0
}
题
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
gapFillingCnt
||
0
}
题
</
div
>
<
div
className=
'item long'
>
{
paperInfo
.
indefiniteChoiceCnt
||
0
}
题
</
div
>
<
div
className=
'item'
>
{
examTotal
}
题
</
div
>
</
div
>
<
div
className=
'body-list'
>
<
div
className=
'item'
>
{
paperInfo
.
singleChoiceScore
||
0
}
分
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
multiChoiceScore
||
0
}
分
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
judgeScore
||
0
}
分
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
gapFillingScore
||
0
}
分
</
div
>
<
div
className=
'item long'
>
{
paperInfo
.
indefiniteChoiceScore
||
0
}
分
</
div
>
<
div
className=
'item'
>
{
paperInfo
.
totalScore
||
0
}
分
</
div
>
</
div
>
</
div
>
)
}
</
Form
.
Item
>
<
Form
.
Item
label=
'考试名称'
validateStatus=
{
check
&&
(
!
examName
||
examName
.
length
>
40
)
?
'error'
:
''
}
help=
{
check
&&
((
!
examName
&&
'请输入考试名称'
)
||
(
examName
.
length
>
40
&&
'考试名称最多40字'
))
}
required
>
<
Input
placeholder=
'请输入考试名称(40字以内)'
maxLength=
{
40
}
value=
{
examName
}
onChange=
{
(
e
)
=>
{
setExamName
(
e
.
target
.
value
);
}
}
style=
{
{
width
:
300
}
}
/>
</
Form
.
Item
>
<
Form
.
Item
label=
{
<
div
>
<
span
>
及格线
</
span
>
<
Tooltip
title=
'默认为选中试卷所设置的及格线,可修改'
>
<
span
className=
'icon iconfont'
style=
{
{
color
:
'#BFBFBF'
,
marginLeft
:
4
}
}
>

</
span
>
</
Tooltip
>
</
div
>
}
style=
{
{
marginTop
:
24
}
}
validateStatus=
{
check
&&
!
passRate
?
'error'
:
''
}
help=
{
check
&&
!
passRate
&&
'请输入及格线'
}
required
>
<
InputNumber
value=
{
passRate
}
min=
{
0
}
max=
{
100
}
onChange=
{
(
value
)
=>
{
setPassRate
(
parseInt
(
value
));
}
}
style=
{
{
width
:
100
}
}
/>
<
span
style=
{
{
marginLeft
:
8
}
}
>
%
</
span
>
<
span
style=
{
{
marginLeft
:
16
,
color
:
'#999'
}
}
>
{
` 总分(${paperInfo.totalScore || 0})*及格线(${passRate || 0}%)=及格分数(${passScore})`
}
</
span
>
</
Form
.
Item
>
<
Form
.
Item
label=
'考试时长'
validateStatus=
{
check
&&
(
!
examDuration
||
(
props
.
basicInfo
.
timeType
===
'VALIDITY'
&&
props
.
basicInfo
.
startTime
&&
props
.
basicInfo
.
endTime
&&
props
.
basicInfo
.
startTime
+
examDuration
*
60
*
1000
>
props
.
basicInfo
.
endTime
))
?
'error'
:
''
}
help=
{
check
&&
((
!
examDuration
&&
'请输入考试时长'
)
||
(
props
.
basicInfo
.
timeType
===
'VALIDITY'
&&
props
.
basicInfo
.
startTime
&&
props
.
basicInfo
.
endTime
&&
props
.
basicInfo
.
startTime
+
examDuration
*
60
*
1000
>
props
.
basicInfo
.
endTime
&&
'考试时长不得超过培训有效期时长'
))
}
required
>
<
InputNumber
value=
{
examDuration
}
max=
{
1440
}
min=
{
1
}
onChange=
{
(
value
)
=>
{
setExamDuration
(
parseInt
(
value
));
}
}
style=
{
{
width
:
100
}
}
/>
<
span
style=
{
{
marginLeft
:
8
}
}
>
分钟
</
span
>
<
span
style=
{
{
marginLeft
:
16
,
color
:
'#999'
}
}
>
{
` 时长不能超过1440分钟(24小时)`
}
</
span
>
</
Form
.
Item
>
<
Form
.
Item
label=
'考试说明'
>
<
GraphicsEditor
maxLimit=
{
1000
}
isIntro=
{
true
}
detail=
{
{
content
:
examDesc
,
}
}
onChange=
{
(
val
)
=>
{
setExamDesc
(
val
);
}
}
/>
</
Form
.
Item
>
<
div
className=
'module-title'
style=
{
{
marginTop
:
16
}
}
>
考试设置
</
div
>
<
Form
.
Item
label=
'选项乱序'
required
>
<
div
style=
{
{
display
:
'flex'
,
marginLeft
:
4
}
}
>
<
Switch
checked=
{
needOptionDisorder
==
'OPTION_RANDOM'
}
onChange=
{
(
val
)
=>
{
setNeedOptionDisorder
(
val
?
'OPTION_RANDOM'
:
'OPTION_SORT'
);
}
}
></
Switch
>
<
div
style=
{
{
position
:
'relative'
,
left
:
8
,
color
:
'#999'
}
}
>
{
needOptionDisorder
==
'OPTION_RANDOM'
?
'已开启,选项随机排序'
:
'已关闭,选项按设置顺序排序'
}
</
div
>
</
div
>
</
Form
.
Item
>
<
Form
.
Item
label=
'考试结果查看'
required
>
<
Radio
.
Group
onChange=
{
(
e
)
=>
{
setResultShow
(
e
.
target
.
value
);
}
}
value=
{
resultShow
}
>
<
Radio
value=
{
'IMMEDIATELY'
}
>
交卷后立即显示考试结果
</
Radio
>
<
Radio
value=
{
'AFTER_EXAM_END'
}
>
到达考试截止日期才显示结果
</
Radio
>
</
Radio
.
Group
>
</
Form
.
Item
>
<
Form
.
Item
label=
'考试结果内容'
required
>
<
Radio
.
Group
onChange=
{
(
e
)
=>
{
setResultContent
(
e
.
target
.
value
);
}
}
value=
{
resultContent
}
>
<
Radio
value=
{
'PASS_AND_SCORE'
}
>
显示考试分数和是否及格
</
Radio
>
<
Radio
value=
{
'ONLY_SCORE'
}
>
仅显示考试分数
</
Radio
>
<
Radio
value=
{
'ONLY_PASS'
}
>
仅显示是否及格
</
Radio
>
</
Radio
.
Group
>
</
Form
.
Item
>
<
Form
.
Item
label=
'答案与解析'
required
>
<
Radio
.
Group
onChange=
{
(
e
)
=>
{
setAnswerAnalysis
(
e
.
target
.
value
);
}
}
value=
{
answerAnalysis
}
>
<
Radio
value=
{
'ANALYSE_AND_RIGHT_OR_WRONG'
}
>
显示对错与解析
</
Radio
>
<
Radio
value=
{
'RIGHT_OR_WRONG'
}
>
仅显示对错
</
Radio
>
<
Radio
value=
{
'CAN_NOT_CHECK'
}
>
都不显示
</
Radio
>
</
Radio
.
Group
>
</
Form
.
Item
>
</
Form
>
<
div
className=
'footer shrink-footer'
>
<
Button
onClick=
{
props
.
onClose
}
>
取消
</
Button
>
<
Button
type=
'primary'
onClick=
{
handleSave
}
>
确定
</
Button
>
</
div
>
{
showPaperModal
&&
(
<
SelectPaperModal
onSelect=
{
(
info
)
=>
{
let
newContentList
=
[];
props
.
stageList
.
map
((
item
)
=>
{
if
(
item
.
contentList
&&
item
.
contentList
.
length
>
0
)
{
item
.
contentList
.
map
((
childItem
)
=>
{
newContentList
.
push
(
childItem
);
});
}
});
const
existedPaperId
=
newContentList
.
filter
((
item
)
=>
{
return
item
.
paperId
===
info
.
paperId
;
});
if
(
existedPaperId
.
length
>
0
)
{
setSamePaper
(
true
);
}
else
{
setSamePaper
(
false
);
}
setPaperInfo
(
info
);
}
}
paperInfo=
{
paperInfo
}
close=
{
()
=>
{
setShowPaperModal
(
false
);
}
}
></
SelectPaperModal
>
)
}
</
Drawer
>
);
}
export
default
RelatedExamDrawer
;
src/modules/task-center/train-task/components/RelatedExamDrawer.less
0 → 100644
View file @
b427be83
.related-exam-drawer {
.module-title {
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 24px;
}
.paper-title {
color: #333333;
line-height: 20px;
padding: 10px 12px;
margin-top: 12px;
margin-bottom: 8px;
img {
width: 20px;
height: 20px;
margin-right: 4px;
}
}
.paper-table {
border: 1px solid #e8e8e8;
width: 550px;
.header {
font-weight: 500;
.item {
padding: 10px 16px;
}
}
.body-list {
.item {
padding: 14px 16px;
}
}
.header,
.body-list {
display: flex;
color: #333333;
.item {
box-sizing: border-box;
width: 86px;
&.long {
width: 120px;
}
}
}
}
.footer {
position: fixed;
right: 0;
bottom: 0;
height: 50px;
width: 720px;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 24px;
background: #fff;
border-top: 1px solid #e8e8e8;
z-index: 9999;
.ant-btn {
margin-left: 8px;
}
}
.ant-form-item {
margin-bottom: 24px !important;
.graphics-editor-container {
width: 550px;
height: 130px;
.editor-warning {
top: 130px !important;
}
}
}
}
src/modules/task-center/train-task/components/TrainContent.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-17 18:19:34
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
Component
}
from
'react'
;
import
{
Form
,
Input
,
Collapse
,
Dropdown
,
Menu
,
Modal
}
from
'antd'
;
import
{
sortableContainer
,
sortableElement
,
sortableHandle
}
from
'react-sortable-hoc'
;
import
arrayMove
from
'array-move'
;
import
'./TrainContent.less'
;
import
RelatedCourseDrawer
from
'./RelatedCourseDrawer'
;
import
RelatedExamDrawer
from
'./RelatedExamDrawer'
;
import
ExpiredCourseList
from
'./ExpiredCourseList'
;
import
ENUM
from
'../../enum'
;
import
FormItem
from
'antd/lib/form/FormItem'
;
const
{
Panel
}
=
Collapse
;
const
{
confirm
}
=
Modal
;
const
SortableStageContainer
=
sortableContainer
((
props
)
=>
<
div
{
...
props
}
></
div
>);
const
SortableStageItem
=
sortableElement
((
props
)
=>
<
div
{
...
props
}
>
{
props
.
stageitem
}
</
div
>);
const
SortableContentContainer
=
sortableContainer
((
props
)
=>
<
div
{
...
props
}
></
div
>);
const
SortableContentItem
=
sortableElement
((
props
)
=>
<
div
{
...
props
}
>
{
props
.
contentitem
}
</
div
>);
const
DragHandle
=
sortableHandle
(()
=>
<
span
className=
'icon iconfont drag-btn'
>

</
span
>);
const
courseStateShow
=
{
UN_START
:
{
title
:
'待开播'
,
},
STARTING
:
{
title
:
'直播中'
,
},
FINISH
:
{
title
:
'回放'
,
},
EXPIRED
:
{
title
:
'未成功开课'
,
},
};
const
SortConvert
=
[
'一'
,
'二'
,
'三'
,
'四'
,
'五'
,
'六'
,
'七'
,
'八'
,
'九'
,
'十'
];
class
TrainContent
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
basicInfo
:
props
.
basicInfo
,
stageList
:
props
.
stageList
,
percentCompleteLive
:
props
.
percentCompleteLive
,
percentCompleteVideo
:
props
.
percentCompleteVideo
,
percentCompletePicture
:
props
.
percentCompletePicture
,
showCourseDrawer
:
false
,
showExamDrawer
:
false
,
selectedStageIndex
:
0
,
type
:
window
.
getParameterByName
(
'type'
),
showStandardDetail
:
false
,
// 是否展开高级设置
};
}
setTrianTypeOption
=
(
index
)
=>
{
return
(
<
Menu
>
<
Menu
.
Item
key=
'course'
onClick=
{
()
=>
this
.
setState
({
showCourseDrawer
:
true
,
selectedStageIndex
:
index
})
}
>
<
img
className=
'type-option-icon'
src=
{
ENUM
.
LearningContentIcon
[
'COURSE'
]
}
/>
<
span
className=
'type-option-text'
>
课程
</
span
>
</
Menu
.
Item
>
<
Menu
.
Item
key=
'exam'
onClick=
{
()
=>
this
.
setState
({
showExamDrawer
:
true
,
selectedStageIndex
:
index
})
}
>
<
img
className=
'type-option-icon'
src=
{
ENUM
.
LearningContentIcon
[
'EXAM'
]
}
/>
<
span
className=
'type-option-text'
>
考试
</
span
>
</
Menu
.
Item
>
{
/* <Menu.Item key='homework'>
<img className='type-option-icon' src={ENUM.LearningContentIcon['HOMEWORK']} />
<span className='type-option-text'>实操作业</span>
</Menu.Item> */
}
</
Menu
>
);
};
onStageSortEnd
=
({
oldIndex
,
newIndex
})
=>
{
const
{
stageList
}
=
this
.
state
;
if
(
oldIndex
!==
newIndex
)
{
const
_stageList
=
arrayMove
([].
concat
(
stageList
),
oldIndex
,
newIndex
).
filter
((
el
)
=>
!!
el
);
this
.
setState
(
{
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
}
};
onContentSortEnd
=
({
oldIndex
,
newIndex
},
parentIndex
)
=>
{
const
{
stageList
}
=
this
.
state
;
const
_stageList
=
[...
stageList
];
if
(
oldIndex
!==
newIndex
)
{
_stageList
[
parentIndex
].
contentList
=
arrayMove
([].
concat
(
stageList
[
parentIndex
].
contentList
),
oldIndex
,
newIndex
).
filter
((
el
)
=>
!!
el
);
this
.
setState
(
{
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
}
};
handleRenameStageName
=
(
value
,
item
)
=>
{
const
{
stageList
}
=
this
.
state
;
item
.
stageName
=
value
;
item
.
check
=
true
;
this
.
setState
(
{
stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
stageList
);
}
);
};
handleStageNameBlur
=
(
e
,
item
,
currentIndex
)
=>
{
const
{
value
}
=
e
.
target
;
const
{
stageList
}
=
this
.
state
;
const
sameStageName
=
stageList
.
filter
((
item
,
index
)
=>
{
return
item
.
stageName
===
value
&&
index
!==
currentIndex
;
});
if
(
sameStageName
.
length
>
0
)
{
return
;
}
let
input
=
/^
[\s]
*$/
;
if
(
value
&&
!
input
.
test
(
value
))
{
item
.
type
=
'text'
;
this
.
setState
(
{
stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
stageList
);
}
);
}
};
handleValidatorStageName
=
(
value
,
currentIndex
)
=>
{
const
{
stageList
}
=
this
.
state
;
const
sameStageName
=
stageList
.
filter
((
item
,
index
)
=>
{
return
item
.
stageName
===
value
&&
index
!==
currentIndex
;
});
let
input
=
/^
[\s]
*$/
;
if
(
input
.
test
(
value
)
||
!
value
)
{
return
'请输入阶段名称'
;
}
else
if
(
sameStageName
.
length
>
0
)
{
return
'阶段名称已存在'
;
}
return
false
;
};
// 移除阶段
handleDeleteStage
=
(
index
)
=>
{
return
confirm
({
title
:
'删除阶段'
,
content
:
'删除该阶段会连同课程、作业、考试一起删除,删除后不可恢复,是否仍要删除?'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
okText
:
'删除'
,
okType
:
'danger'
,
cancelText
:
'取消'
,
onOk
:
()
=>
{
this
.
handleConfirmDeleteStage
(
index
);
},
});
};
handleConfirmDeleteStage
=
(
index
)
=>
{
const
{
stageList
}
=
this
.
state
;
const
_stageList
=
[...
stageList
];
_stageList
.
splice
(
index
,
1
);
this
.
setState
(
{
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
};
handleDeleteCourse
=
(
parentIndex
,
index
)
=>
{
return
confirm
({
title
:
'删除学习内容'
,
content
:
'确定删除该学习内容吗?'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
okText
:
'删除'
,
okType
:
'danger'
,
cancelText
:
'取消'
,
onOk
:
()
=>
{
this
.
handleConfirmDeleteCourse
(
parentIndex
,
index
);
},
});
};
handleConfirmDeleteCourse
=
(
parentIndex
,
index
)
=>
{
const
{
stageList
}
=
this
.
state
;
const
_stageList
=
[...
stageList
];
const
selectData
=
[...
_stageList
[
parentIndex
].
contentList
];
selectData
.
splice
(
index
,
1
);
_stageList
[
parentIndex
].
contentList
=
selectData
;
this
.
setState
(
{
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
_stageList
);
}
);
};
renderStageInfo
=
(
item
,
index
)
=>
{
const
{
startCheck
}
=
this
.
props
;
return
(
<
div
className=
'sort-stage-item'
>
<
div
className=
'item-info'
>
<
span
className=
'info-number'
>
{
SortConvert
[
index
]
}
、
</
span
>
<
Choose
>
<
When
condition=
{
item
.
type
===
'input'
}
>
<
Form
>
<
Form
.
Item
initialValue=
{
item
.
stageName
}
validateStatus=
{
(
item
.
check
||
startCheck
)
&&
this
.
handleValidatorStageName
(
item
.
stageName
,
index
)
?
'error'
:
''
}
help=
{
(
item
.
check
||
startCheck
)
&&
this
.
handleValidatorStageName
(
item
.
stageName
,
index
)
}
>
<
Input
className=
'info-input'
style=
{
{
width
:
300
}
}
placeholder=
'请输入阶段名称'
maxLength=
{
20
}
value=
{
item
.
stageName
}
onChange=
{
(
e
)
=>
{
this
.
handleRenameStageName
(
e
.
target
.
value
,
item
);
}
}
onBlur=
{
(
e
)
=>
{
this
.
handleStageNameBlur
(
e
,
item
,
index
);
}
}
/>
</
Form
.
Item
>
</
Form
>
</
When
>
<
Otherwise
>
<
span
className=
'info-text'
>
{
item
.
stageName
}
</
span
>
</
Otherwise
>
</
Choose
>
</
div
>
<
span
className=
'item-operate'
>
<
span
className=
'operate__item'
onClick=
{
(
e
)
=>
{
if
(
item
.
type
===
'input'
)
return
;
const
{
stageList
}
=
this
.
state
;
item
.
type
=
'input'
;
item
.
check
=
true
;
this
.
setState
({
stageList
});
e
.
stopPropagation
();
}
}
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'text'
>
重命名
</
span
>
</
span
>
<
span
className=
'operate__item'
style=
{
{
marginLeft
:
16
}
}
onClick=
{
(
e
)
=>
{
this
.
handleDeleteStage
(
index
);
e
.
stopPropagation
();
}
}
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'text'
>
删除
</
span
>
</
span
>
</
span
>
<
DragHandle
/>
</
div
>
);
};
renderStageItem
=
(
item
,
index
)
=>
{
return
(
<
Collapse
defaultActiveKey=
{
this
.
state
.
type
===
'add'
&&
[
'1'
]
}
ghost
>
<
Panel
header=
{
this
.
renderStageInfo
(
item
,
index
)
}
key=
{
item
.
sequence
}
>
<
SortableContentContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
(
item
)
=>
this
.
onContentSortEnd
(
item
,
index
)
}
>
{
item
.
contentList
.
map
((
contentItem
,
contentIndex
)
=>
(
<
SortableContentItem
contentitem=
{
this
.
renderContentItem
(
contentItem
,
contentIndex
,
index
)
}
index=
{
contentIndex
}
key=
{
contentIndex
}
></
SortableContentItem
>
))
}
</
SortableContentContainer
>
<
Dropdown
overlay=
{
this
.
setTrianTypeOption
(
index
)
}
>
<
span
className=
{
`add-content-btn ${item.contentList.length === 20 && 'disabled'}`
}
>
+ 添加学习内容
</
span
>
</
Dropdown
>
</
Panel
>
</
Collapse
>
);
};
renderContentItem
=
(
record
,
index
,
parentIndex
)
=>
{
const
{
courseState
,
contentName
,
contentType
,
courseType
,
courseChapterNum
}
=
record
;
return
(
<
div
className=
'sort-content-item'
>
<
div
className=
'content-info'
>
<
img
className=
'type-option-icon'
src=
{
ENUM
.
LearningContentIcon
[
courseType
||
contentType
]
}
/>
<
span
className=
'content-name'
>
{
parentIndex
+
1
}
.
{
index
+
1
}
{
contentName
}
</
span
>
{
courseState
===
'EXPIRED'
&&
<
span
className=
'icon iconfont tip'
>

</
span
>
}
{
courseType
===
'LIVE'
&&
<
span
className=
'extra-info'
>
{
courseStateShow
[
courseState
].
title
}
</
span
>
}
{
courseType
===
'VOICE'
&&
<
span
className=
'extra-info'
>
(共
{
courseChapterNum
||
1
}
小节)
</
span
>
}
</
div
>
<
div
className=
'content-operate'
>
<
span
className=
'operate__item'
onClick=
{
()
=>
{
this
.
handleDeleteCourse
(
parentIndex
,
index
);
}
}
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'text'
>
删除
</
span
>
</
span
>
</
div
>
<
DragHandle
/>
</
div
>
);
};
// 添加阶段
addStage
=
()
=>
{
const
{
stageList
}
=
this
.
state
;
const
stageObj
=
{
stageName
:
''
,
type
:
'input'
,
contentList
:
[],
check
:
false
,
};
const
_stageList
=
[...
stageList
,
stageObj
];
this
.
setState
(
{
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
};
onCloseCourseDrawer
=
()
=>
{
this
.
setState
({
showCourseDrawer
:
false
,
});
};
onCloseExamDrawer
=
()
=>
{
this
.
setState
({
showExamDrawer
:
false
,
});
};
confirmSelectCourse
=
(
selectList
)
=>
{
const
{
selectedStageIndex
}
=
this
.
state
;
const
{
stageList
}
=
this
.
state
;
const
_stageList
=
[...
stageList
];
const
selectData
=
[...
_stageList
[
selectedStageIndex
].
contentList
];
let
_selectList
=
[];
selectList
.
forEach
((
item
)
=>
{
_selectList
.
push
({
contentId
:
item
.
courseId
,
contentName
:
item
.
courseName
,
contentType
:
'COURSE'
,
courseType
:
item
.
courseType
,
courseState
:
item
.
courseState
,
});
});
const
_selectData
=
[...
selectData
,
...
_selectList
];
_stageList
[
selectedStageIndex
].
contentList
=
_selectData
;
this
.
setState
(
{
showCourseDrawer
:
false
,
stageList
:
_stageList
,
},
()
=>
{
console
.
log
(
'_stageList=============>'
,
_stageList
);
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
};
confirmCreateExam
=
(
examInfo
)
=>
{
const
{
selectedStageIndex
}
=
this
.
state
;
const
{
stageList
}
=
this
.
state
;
const
_stageList
=
[...
stageList
];
const
selectData
=
[...
_stageList
[
selectedStageIndex
].
contentList
];
const
_examInfo
=
{
contentId
:
examInfo
.
examId
,
contentName
:
examInfo
.
examName
,
contentType
:
'EXAM'
,
paperId
:
examInfo
.
paperId
,
};
selectData
.
push
(
_examInfo
);
_stageList
[
selectedStageIndex
].
contentList
=
selectData
;
this
.
setState
(
{
showExamDrawer
:
false
,
stageList
:
_stageList
,
},
()
=>
{
this
.
props
.
onChange
(
'stageList'
,
_stageList
);
}
);
};
changePercentComplete
=
(
e
,
field
)
=>
{
let
_percentComplete
=
0
;
const
value
=
e
.
target
.
value
.
replace
(
/
\D
/g
,
''
);
if
(
value
>
100
)
{
_percentComplete
=
100
;
}
else
{
if
(
value
<
0
)
{
_percentComplete
=
0
;
}
else
{
_percentComplete
=
value
;
}
}
this
.
setState
(
{
[
field
]:
_percentComplete
,
},
()
=>
{
this
.
props
.
onChange
(
field
,
_percentComplete
);
}
);
};
render
()
{
const
{
stageList
,
showCourseDrawer
,
showExamDrawer
,
showStandardDetail
,
basicInfo
,
selectedStageIndex
,
percentCompleteLive
,
percentCompleteVideo
,
percentCompletePicture
,
type
,
}
=
this
.
state
;
const
{
startCheck
}
=
this
.
props
;
const
taskId
=
window
.
getParameterByName
(
'taskId'
);
return
(
<
div
className=
'train-content-page'
>
<
div
className=
'train-content__warp'
>
<
SortableStageContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
this
.
onStageSortEnd
}
>
{
stageList
.
map
((
item
,
index
)
=>
(
<
SortableStageItem
stageitem=
{
this
.
renderStageItem
(
item
,
index
)
}
index=
{
index
}
key=
{
index
}
></
SortableStageItem
>
))
}
</
SortableStageContainer
>
{
stageList
.
length
<
10
&&
(
<
div
className=
'add-stage-btn'
onClick=
{
()
=>
this
.
addStage
()
}
>
+ 添加阶段
</
div
>
)
}
{
showCourseDrawer
&&
(
<
RelatedCourseDrawer
data=
{
stageList
}
selectedStageIndex=
{
selectedStageIndex
}
onClose=
{
this
.
onCloseCourseDrawer
}
onSelect=
{
this
.
confirmSelectCourse
}
/>
)
}
{
showExamDrawer
&&
<
RelatedExamDrawer
basicInfo=
{
basicInfo
}
stageList=
{
stageList
}
onClose=
{
this
.
onCloseExamDrawer
}
onSave=
{
this
.
confirmCreateExam
}
/>
}
</
div
>
{
type
===
'edit'
&&
<
ExpiredCourseList
taskId=
{
taskId
}
/>
}
<
div
className=
'finish-standard__warp'
>
<
div
className=
'module-title'
onClick=
{
()
=>
{
this
.
setState
({
showStandardDetail
:
!
showStandardDetail
});
}
}
>
高级设置
<
span
className=
{
`icon iconfont ${showStandardDetail && 'rotate-arrow'}`
}
>

</
span
>
</
div
>
{
showStandardDetail
&&
(
<
div
className=
'detail-container'
>
<
div
className=
'title-text'
>
完成标准:
</
div
>
<
Form
className=
'detail-box'
>
<
div
className=
'item-info'
>
<
span
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
'LIVE'
]
}
/>
</
span
>
<
span
>
直播课单个课程,学员学习进度达到
<
FormItem
validateStatus=
{
startCheck
&&
percentCompleteLive
===
''
?
'error'
:
''
}
help=
{
startCheck
&&
percentCompleteLive
===
''
&&
'请输入完成标准'
}
>
<
Input
value=
{
percentCompleteLive
}
onChange=
{
(
e
)
=>
{
this
.
changePercentComplete
(
e
,
'percentCompleteLive'
);
}
}
className=
'input-box'
/>
</
FormItem
>
%,即视为"已完成"学习
</
span
>
</
div
>
<
div
className=
'item-info'
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
'VOICE'
]
}
/>
<
span
>
线上课单个课节,学员学习进度达到
<
FormItem
validateStatus=
{
startCheck
&&
percentCompleteVideo
===
''
?
'error'
:
''
}
help=
{
startCheck
&&
percentCompleteVideo
===
''
&&
'请输入完成标准'
}
>
<
Input
value=
{
percentCompleteVideo
}
onChange=
{
(
e
)
=>
{
this
.
changePercentComplete
(
e
,
'percentCompleteVideo'
);
}
}
className=
'input-box'
/>
</
FormItem
>
%,即课节视为"已完成"学习
</
span
>
</
div
>
<
div
className=
'item-info'
>
<
img
src=
{
ENUM
.
LearningContentIcon
[
'PICTURE'
]
}
/>
<
span
>
图文课单个课程,学员学习进度达到
<
FormItem
validateStatus=
{
startCheck
&&
percentCompletePicture
===
''
?
'error'
:
''
}
help=
{
startCheck
&&
percentCompletePicture
===
''
&&
'请输入完成标准'
}
>
<
Input
value=
{
percentCompletePicture
}
onChange=
{
(
e
)
=>
{
this
.
changePercentComplete
(
e
,
'percentCompletePicture'
);
}
}
className=
'input-box'
/>
</
FormItem
>
%,即视为"已完成"学习
</
span
>
</
div
>
</
Form
>
</
div
>
)
}
</
div
>
</
div
>
);
}
}
export
default
TrainContent
;
src/modules/task-center/train-task/components/TrainContent.less
0 → 100644
View file @
b427be83
.train-content-page {
.train-content__warp {
.ant-collapse-header {
padding: 15px 16px !important;
background-color: #f7f8f9;
}
.add-stage-btn {
color: #2966ff;
height: 52px;
background: #f7f8f9;
padding: 16px;
cursor: pointer;
}
}
.expired-info__wrap {
margin-top: 24px;
.module-title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
}
}
.finish-standard__warp {
margin-top: 24px;
margin-bottom: 60px;
.module-title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
cursor: pointer;
.icon {
font-size: 12px;
margin-left: 8px;
color: #5e606a;
display: inline-block;
vertical-align: middle;
}
.rotate-arrow {
transform: (rotate(180deg));
}
}
.detail-container {
margin-top: 24px;
display: flex;
.title-text {
color: #333333;
line-height: 20px;
}
.detail-box {
margin-top: -4px;
.item-info {
color: #333333;
vertical-align: middle;
margin-bottom: 20px;
.ant-form-item {
display: inline-block;
margin-bottom: 0 !important;
vertical-align: baseline;
}
img {
width: 20px;
height: 20px;
margin-right: 8px;
}
.input-box {
width: 60px;
height: 32px;
border-radius: 2px;
border: 1px solid #e8e8e8;
margin: 0 4px;
}
}
}
}
}
}
.sort-stage-item {
width: calc(100% - 24px);
display: inline-flex;
align-items: center;
line-height: 20px;
.item-info {
color: #333333;
}
.item-operate {
display: none;
margin-left: 30px;
.operate__item {
cursor: pointer;
.icon {
color: #bfbfbf;
font-size: 14px;
}
.text {
color: #666666;
margin-left: 8px;
}
}
}
&:hover {
.item-operate {
display: block;
}
}
.ant-form {
display: inline-block;
.ant-form-item {
margin-bottom: 0 !important;
}
}
}
.sort-content-item {
display: flex;
padding: 15px 16px !important;
margin-left: 40px;
justify-content: space-between;
align-items: center;
border-bottom: 1px dotted #e8e8e8;
vertical-align: middle;
* {
vertical-align: middle;
height: 20px;
}
&:hover {
.content-operate {
display: block;
}
}
.content-info {
.content-name {
color: #333333;
font-size: 14px;
margin-left: 12px;
}
.extra-info {
color: #999999;
margin-left: 12px;
}
.tip {
font-size: 14px;
color: #ff4f4f;
margin-right: 2px;
}
}
.content-operate {
display: none;
margin-left: 26px;
.operate__item {
cursor: pointer;
color: #666666;
.icon {
font-size: 14px;
color: #bfbfbf;
}
.text {
margin-left: 8px;
}
}
}
}
.type-option-icon {
width: 20px;
height: 20px;
}
.type-option-text {
margin-left: 12px;
}
.drag-btn {
margin-left: auto;
color: #cccccc;
cursor: pointer;
}
.add-content-btn {
color: #2966ff;
height: 52px;
border-radius: 2px;
padding: 16px;
cursor: pointer;
display: inline-block;
&.disabled {
color: #ccc;
cursor: not-allowed;
pointer-events: none;
}
}
.ant-collapse-content {
padding-left: 24px !important;
> .ant-collapse-content-box {
padding: 0 !important;
}
}
src/modules/task-center/train-task/components/TrainFilter.jsx
0 → 100644
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-07-14 15:41:30
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-07-23 13:45:16
* @Description: 大班直播、互动班课列表的筛选组件
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Row
,
Input
,
Select
,
Tooltip
}
from
'antd'
;
import
RangePicker
from
'@/modules/common/DateRangePicker'
;
import
moment
from
'moment'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
'./TrainFilter.less'
;
const
{
Search
}
=
Input
;
const
DEFAULT_QUERY
=
{
// 头部筛选默认值
taskName
:
null
,
createId
:
null
,
// 创建人
startTime
:
null
,
endTime
:
null
,
};
const
DEFAULT_CREATOR_QUERY
=
{
// 创建人列表筛选默认值
size
:
10
,
current
:
1
,
nickName
:
null
,
// 搜索值
};
function
TrainFilter
(
props
)
{
const
[
query
,
setQuery
]
=
useState
(
DEFAULT_QUERY
);
const
[
hasNext
,
setHasNext
]
=
useState
(
false
);
const
[
creatorQuery
,
setCreatorQuery
]
=
useState
(
DEFAULT_CREATOR_QUERY
);
const
[
creatorList
,
setCreatorList
]
=
useState
([]);
useEffect
(()
=>
{
getCreatorList
();
},
[]);
// 获取创建人列表
function
getCreatorList
(
current
=
1
)
{
const
_query
=
{
...
creatorQuery
,
current
,
};
StoreService
.
getStoreUserBasicPage
(
_query
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
hasNext
}
=
result
;
const
list
=
current
>
1
?
creatorList
.
concat
(
records
)
:
records
;
setHasNext
(
hasNext
);
setCreatorList
(
list
);
});
}
// 滑动加载更多创建人列表(讲师)
function
handleScrollCreatorList
(
e
)
{
const
container
=
e
.
target
;
const
scrollToBottom
=
container
&&
container
.
scrollHeight
<=
container
.
clientHeight
+
container
.
scrollTop
;
if
(
scrollToBottom
&&
hasNext
)
{
const
_creatorQuery
=
{
...
creatorQuery
};
_creatorQuery
.
current
=
creatorQuery
.
current
+
1
;
setCreatorQuery
(
_creatorQuery
);
getCreatorList
(
creatorQuery
.
current
+
1
);
}
}
// 改变搜索条件
function
handleChangeQuery
(
field
,
value
)
{
const
_query
=
_
.
clone
(
query
);
_query
.
current
=
1
;
if
(
field
===
'createdDate'
)
{
_query
.
startTime
=
value
[
0
]?.
startOf
(
'day'
).
valueOf
();
_query
.
endTime
=
value
[
1
]?.
endOf
(
'day'
).
valueOf
();
}
else
{
_query
[
field
]
=
value
;
}
setQuery
(
_query
);
if
(
field
===
'taskName'
)
return
;
props
.
onChange
(
_query
);
}
// 重置搜索条件
function
handleReset
()
{
setQuery
(
DEFAULT_QUERY
);
props
.
onChange
(
DEFAULT_QUERY
);
}
return
(
<
div
className=
'train-filter-page'
>
<
Row
>
<
div
className=
'search-condition'
>
<
div
className=
'search-condition__item'
>
<
span
>
培训任务:
</
span
>
<
Search
value=
{
query
.
taskName
}
placeholder=
'搜索培训任务名称'
onChange=
{
(
e
)
=>
{
handleChangeQuery
(
'taskName'
,
e
.
target
.
value
.
trim
());
}
}
onSearch=
{
()
=>
{
props
.
onChange
(
query
);
}
}
style=
{
{
width
:
'calc(100% - 70px)'
}
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
/>
</
div
>
<
div
className=
'search-condition__item'
>
<
span
>
创建人:
</
span
>
<
Select
placeholder=
'请选择创建人'
style=
{
{
width
:
'calc(100% - 70px)'
}
}
showSearch
allowClear
filterOption=
{
(
input
,
option
)
=>
option
}
suffixIcon=
{
<
span
className=
'icon iconfont'
style=
{
{
fontSize
:
'12px'
,
color
:
'#BFBFBF'
}
}
>

</
span
>
}
onPopupScroll=
{
handleScrollCreatorList
}
value=
{
query
.
createId
}
onChange=
{
(
value
)
=>
{
handleChangeQuery
(
'createId'
,
value
);
}
}
onSearch=
{
(
value
)
=>
{
creatorQuery
.
nickName
=
value
;
setCreatorQuery
(
creatorQuery
);
getCreatorList
();
}
}
onClear=
{
()
=>
{
setCreatorQuery
(
DEFAULT_CREATOR_QUERY
);
getCreatorList
();
}
}
>
{
_
.
map
(
creatorList
,
(
item
,
index
)
=>
{
return
(
<
Select
.
Option
value=
{
item
.
id
}
key=
{
item
.
id
}
>
{
item
.
nickName
}
</
Select
.
Option
>
);
})
}
</
Select
>
</
div
>
<
div
className=
'search-condition__item'
>
<
span
className=
'search-date'
>
创建日期:
</
span
>
<
RangePicker
id=
'train_date_picker'
allowClear=
{
false
}
value=
{
query
.
startTime
?
[
moment
(
query
.
startTime
),
moment
(
query
.
endTime
)]
:
null
}
format=
{
'YYYY-MM-DD'
}
onChange=
{
(
value
)
=>
{
handleChangeQuery
(
'createdDate'
,
value
);
}
}
style=
{
{
width
:
'calc(100% - 70px)'
}
}
/>
</
div
>
</
div
>
<
div
className=
'reset-fold-area'
>
<
Tooltip
title=
'清空筛选'
>
<
span
className=
'resetBtn iconfont icon'
onClick=
{
handleReset
}
>

{
' '
}
</
span
>
</
Tooltip
>
</
div
>
</
Row
>
</
div
>
);
}
export
default
TrainFilter
;
src/modules/task-center/train-task/components/TrainFilter.less
0 → 100644
View file @
b427be83
.train-filter-page {
.search-condition {
width: calc(100% - 80px);
display: flex;
align-items: center;
flex-wrap: wrap;
&__item {
width: 30%;
margin-right: 3%;
line-height: 32px;
}
}
.reset-fold-area {
position: absolute;
right: 12px;
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
}
}
src/modules/task-center/train-task/components/TrainList.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-07-28 14:56:52
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 12:37:50
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
}
from
'react'
;
import
{
withRouter
}
from
'react-router-dom'
;
import
{
Tooltip
,
Checkbox
,
Dropdown
,
Radio
,
Button
,
Space
,
Modal
,
message
}
from
'antd'
;
import
'./TrainList.less'
;
import
{
XMTable
,
PageControl
}
from
'@/components'
;
import
User
from
'@/common/js/user'
;
import
ENUM
from
'../../enum'
;
import
TaskCenterService
from
'@/domains/task-center-domain/TaskCenterService'
;
import
ShareTrainTaskModal
from
'../modal/ShareTrainTaskModal'
;
import
ChooseAssignorModal
from
'../modal/ChooseAssignorModal'
;
import
{
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
;
import
Bus
from
'@/core/bus'
;
function
TrainList
(
props
)
{
const
{
query
:
{
issueState
,
myAssist
,
current
,
size
},
totalCount
,
match
,
}
=
props
;
const
[
shareTrainTaskModal
,
setShareTrainTaskModal
]
=
useState
(
null
);
const
[
chooseAssignorModal
,
setChooseAssignorModal
]
=
useState
(
null
);
// 发布或取消发布培训任务
function
updateIssueStateTrain
(
taskId
,
state
)
{
Modal
.
confirm
({
title
:
'提示'
,
content
:
state
===
'YES'
?
'发布后,被指派学员将任务列表中看到该任务,确定要发布?'
:
'取消发布后,任务对学员暂不可见,可能会影响正在学习学员,确定要取消?'
,
okText
:
'确定'
,
cancelText
:
'取消'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
onOk
:
()
=>
{
TaskCenterService
.
updateIssueStateTraining
({
taskId
,
issueState
:
state
,
}).
then
((
res
)
=>
{
message
.
success
(
state
===
'YES'
?
'发布成功'
:
'取消发布成功'
);
Bus
.
trigger
(
'getTrainingTaskPage'
,
{
issueState
,
myAssist
});
Bus
.
trigger
(
'getStoreTaskNum'
);
});
},
});
}
// 删除培训任务
function
deleteTrainTask
(
taskId
)
{
Modal
.
confirm
({
title
:
'你确定要删除吗?'
,
content
:
'删除后,此培训任务的用户将无法继续学习,所有学习数据将同步删除不可恢复'
,
okText
:
'确定'
,
cancelText
:
'取消'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
onOk
:
()
=>
{
TaskCenterService
.
deleteTrainingTask
({
taskId
,
}).
then
((
res
)
=>
{
message
.
success
(
'删除成功'
);
Bus
.
trigger
(
'getTrainingTaskPage'
,
{
issueState
,
myAssist
});
Bus
.
trigger
(
'getStoreTaskNum'
);
});
},
});
}
// 编辑培训任务-跳转新建/编辑页
function
editTrainingTask
(
item
)
{
window
.
RCHistory
.
push
({
pathname
:
`/create-train-task?type=edit&taskId=
${
item
.
taskId
}
&taskState=
${
item
.
taskState
}
&timeType=
${
item
.
timeType
}
`
,
});
}
// 显示指派弹窗
function
handleShowAssignModal
(
item
)
{
let
_assignList
=
[];
if
(
item
.
assignList
?.
length
>
0
)
{
_assignList
=
item
.
assignList
.
map
((
childItem
)
=>
{
childItem
.
checkedId
=
childItem
.
assignId
;
childItem
.
checkedName
=
childItem
.
assignName
;
childItem
.
checkedType
=
childItem
.
assignType
;
return
childItem
;
});
}
const
chooseAssignorModal
=
(
<
ChooseAssignorModal
currentAssignorList=
{
_assignList
}
visible=
{
true
}
onClose=
{
()
=>
{
setChooseAssignorModal
(
null
);
}
}
onConfirm=
{
(
data
)
=>
{
confirmUpdatedAssignor
(
data
,
item
.
taskId
);
}
}
/>
);
setChooseAssignorModal
(
chooseAssignorModal
);
}
// 显示分享弹窗
function
handleShowShareModal
(
item
)
{
const
htmlUrl
=
`
${
LIVE_SHARE
}
training_task_detail/
${
item
.
taskId
}
?id=
${
User
.
getStoreId
()}
&storeUserId=
${
User
.
getStoreUserId
()}
`
;
const
longUrl
=
htmlUrl
;
const
shareData
=
{
...
item
,
longUrl
};
const
shareTrainTaskModal
=
(
<
ShareTrainTaskModal
data=
{
shareData
}
type=
'liveClass'
close=
{
()
=>
{
setShareTrainTaskModal
(
null
);
}
}
/>
);
setShareTrainTaskModal
(
shareTrainTaskModal
);
}
// 确定指派人员
function
confirmUpdatedAssignor
(
data
,
id
)
{
const
assignList
=
data
.
map
((
item
)
=>
{
return
{
assignType
:
item
.
checkedType
,
assignId
:
item
.
checkedId
,
};
});
const
params
=
{
assignList
,
id
,
};
if
(
assignList
.
length
===
0
)
{
return
message
.
warning
(
'指派列表不能为空'
);
}
TaskCenterService
.
updateTrainingTaskAssign
(
params
).
then
((
res
)
=>
{
message
.
success
(
'指派成功'
);
Bus
.
trigger
(
'getTrainingTaskPage'
,
{
issueState
,
myAssist
});
setChooseAssignorModal
(
null
);
});
}
function
renderMoreOperate
(
item
)
{
const
isUnableIssue
=
item
.
issueState
===
'YES'
;
// 已发布
const
isUnableAbleEdit
=
item
.
issueState
===
'YES'
||
item
.
taskState
===
'FINISH'
;
// 已发布或已结束
const
isUnableShare
=
item
.
issueState
===
'NO'
||
item
.
taskState
===
'FINISH'
;
//未发布或已结束
return
(
<
div
className=
'train-list-more-menu'
>
{
!
isUnableIssue
&&
(
<
div
className=
'operate__item'
onClick=
{
()
=>
updateIssueStateTrain
(
item
.
taskId
,
'YES'
)
}
>
发布
</
div
>
)
}
{
isUnableIssue
&&
(
<
div
className=
'operate__item'
onClick=
{
()
=>
updateIssueStateTrain
(
item
.
taskId
,
'NO'
)
}
>
取消发布
</
div
>
)
}
<
div
className=
{
`operate__item ${isUnableAbleEdit && 'disabled'} `
}
onClick=
{
()
=>
{
editTrainingTask
(
item
);
}
}
>
编辑
</
div
>
<
div
className=
{
`operate__item ${isUnableShare && 'disabled'} `
}
onClick=
{
()
=>
handleShowShareModal
(
item
)
}
>
分享
</
div
>
{
/* <div className='operate__item'>审批作业</div> */
}
<
div
className=
'operate__item'
onClick=
{
()
=>
{
deleteTrainTask
(
item
.
taskId
);
}
}
>
删除
</
div
>
</
div
>
);
}
function
parseColumns
()
{
const
columns
=
[
{
title
:
'培训任务'
,
key
:
'taskName'
,
dataIndex
:
'taskName'
,
width
:
'18%'
,
fixed
:
'left'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'train-task-name'
>
<
img
className=
'train-cover'
src=
{
record
.
coverUrl
||
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
}
alt=
''
/>
<
Choose
>
<
When
condition=
{
record
.
taskName
?.
length
>
25
}
>
<
Tooltip
title=
{
record
.
taskName
}
>
<
div
className=
'train-name'
>
{
val
}
</
div
>
</
Tooltip
>
</
When
>
<
Otherwise
>
<
div
className=
'train-name'
>
{
val
}
</
div
>
</
Otherwise
>
</
Choose
>
</
div
>
);
},
},
{
title
:
'任务状态'
,
width
:
'12%'
,
key
:
'taskState'
,
dataIndex
:
'taskState'
,
render
:
(
val
)
=>
{
return
(
<
div
className=
'task-state'
>
<
span
className=
'status-point'
style=
{
{
backgroundColor
:
ENUM
.
trainStatus
[
val
||
'UN_START'
].
color
}
}
></
span
>
<
span
>
{
ENUM
.
trainStatus
[
val
||
'UN_START'
].
text
}
</
span
>
</
div
>
);
},
},
{
title
:
'任务数'
,
width
:
'8%'
,
key
:
'contentNum'
,
dataIndex
:
'contentNum'
,
render
:
(
val
,
record
)
=>
{
return
<
span
>
{
val
}
</
span
>;
},
},
{
title
:
'学习人数'
,
width
:
'12%'
,
key
:
'cultureCustomerNum'
,
dataIndex
:
'cultureCustomerNum'
,
render
:
(
val
,
record
)
=>
{
return
(
<
Tooltip
title=
{
<
div
>
<
div
>
未完成:
{
record
.
startingCustomerNum
}
人
</
div
>
<
div
>
已完成:
{
record
.
finishCustomerNum
}
人
</
div
>
<
div
>
已逾期:
{
record
.
overdueCustomerNum
}
人
</
div
>
</
div
>
}
>
<
span
style=
{
{
color
:
'#2966FF'
,
cursor
:
'pointer'
}
}
onClick=
{
()
=>
{
props
.
history
.
push
(
`${match.path}/data/${record.taskId}`
);
}
}
>
{
val
}
</
span
>
</
Tooltip
>
);
},
},
{
title
:
(
<
span
>
完成率
<
Tooltip
title=
'完成培训任务的人数/学习总人数'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'4px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'normal'
,
}
}
>

</
i
>
</
Tooltip
>
</
span
>
),
width
:
'11.5%'
,
key
:
'finishPercent'
,
dataIndex
:
'finishPercent'
,
render
:
(
val
)
=>
{
return
<
span
>
{
val
}
%
</
span
>;
},
},
{
title
:
'培训时间'
,
width
:
'17%'
,
key
:
'trainTime'
,
dataIndex
:
'trainTime'
,
render
:
(
val
,
record
)
=>
{
if
(
record
.
timeType
===
'FOREVER'
)
{
return
<
span
>
不限时
</
span
>;
}
return
(
<
span
>
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
record
.
startTime
)
}
~
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
record
.
endTime
)
}
</
span
>
);
},
},
{
title
:
'创建人'
,
key
:
'createName'
,
dataIndex
:
'createName'
,
width
:
'12%'
,
render
:
(
val
)
=>
{
return
<
span
>
{
val
}
</
span
>;
},
},
{
title
:
'创建时间'
,
width
:
'14%'
,
key
:
'created'
,
dataIndex
:
'created'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
<
span
style=
{
{
whiteSpace
:
'nowrap'
}
}
>
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>;
},
},
{
title
:
'更新时间'
,
width
:
'14%'
,
key
:
'updated'
,
dataIndex
:
'updated'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
<
span
style=
{
{
whiteSpace
:
'nowrap'
}
}
>
{
window
.
formatDate
(
'YYYY-MM-DD H:i'
,
val
)
}
</
span
>;
},
},
{
title
:
'操作'
,
key
:
'operate'
,
dataIndex
:
'operate'
,
fixed
:
'right'
,
width
:
'18%'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'operate'
>
<
div
className=
'operate__item'
onClick=
{
()
=>
{
props
.
history
.
push
(
`${match.path}/data/${record.taskId}`
);
}
}
>
数据
</
div
>
<
span
className=
'split'
>
|
</
span
>
<
div
className=
{
`operate__item ${record.taskState === 'FINISH' && 'disabled'} `
}
onClick=
{
()
=>
{
handleShowAssignModal
(
record
);
}
}
>
指派
</
div
>
<
span
className=
'split'
>
|
</
span
>
<
Dropdown
overlay=
{
renderMoreOperate
(
record
)
}
>
<
span
className=
'more-operate'
>
<
span
className=
'more-text'
>
更多
</
span
>
<
span
className=
'iconfont icon'
style=
{
{
color
:
'#2966FF'
}
}
>

</
span
>
</
span
>
</
Dropdown
>
</
div
>
);
},
},
];
return
columns
;
}
// 改变搜索条件(状态 协同与否)
function
handleChangeQuery
(
field
,
value
)
{
const
_query
=
{
...
props
.
query
,
[
field
]:
value
,
current
:
1
,
};
props
.
onChange
(
_query
);
}
function
handleChangeTable
(
pagination
,
filters
,
sorter
)
{
const
{
columnKey
,
order
}
=
sorter
;
const
{
query
}
=
props
;
let
_columnKey
;
let
_order
;
if
(
columnKey
===
'created'
&&
order
===
'ascend'
)
{
// 按创建时间升序排序
_columnKey
=
'CREATED'
;
_order
=
'SORT_ASC'
;
}
if
(
columnKey
===
'created'
&&
order
===
'descend'
)
{
// 按创建时间降序排序
_columnKey
=
'CREATED'
;
_order
=
'SORT_DESC'
;
}
if
(
columnKey
===
'updated'
&&
order
===
'ascend'
)
{
// 按更新时间升序排序
_columnKey
=
'UPDATED'
;
_order
=
'SORT_ASC'
;
}
if
(
columnKey
===
'updated'
&&
order
===
'descend'
)
{
// 按更新时间降序排序
_columnKey
=
'UPDATED'
;
_order
=
'SORT_DESC'
;
}
const
_query
=
{
...
query
,
sortMap
:
{
UPDATED
:
'SORT_DESC'
,
},
};
_query
.
sortMap
[
_columnKey
]
=
_order
;
props
.
onChange
(
_query
);
}
function
handleCreateTask
()
{
window
.
RCHistory
.
push
({
pathname
:
'/create-train-task?type=add'
,
});
}
return
(
<
div
className=
'train-list-page'
>
<
div
className=
'header-line'
>
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<
Button
type=
'primary'
className=
'mr12'
onClick=
{
handleCreateTask
}
>
新建培训任务
</
Button
>
)
}
<
Space
size=
{
16
}
>
<
Radio
.
Group
size=
'middle'
value=
{
issueState
}
onChange=
{
(
e
)
=>
{
handleChangeQuery
(
'issueState'
,
e
.
target
.
value
);
}
}
>
<
Radio
.
Button
value=
'ALL'
>
全部(
{
props
.
storeTaskNum
.
allNum
}
)
</
Radio
.
Button
>
<
Radio
.
Button
value=
'YES'
>
已发布(
{
props
.
storeTaskNum
.
issueNum
}
)
</
Radio
.
Button
>
<
Radio
.
Button
value=
'NO'
>
未发布(
{
props
.
storeTaskNum
.
notIssueNum
}
)
</
Radio
.
Button
>
</
Radio
.
Group
>
<
Checkbox
style=
{
{
lineHeight
:
'32px'
}
}
value=
{
myAssist
}
onChange=
{
(
e
)
=>
handleChangeQuery
(
'myAssist'
,
e
.
target
.
checked
)
}
>
只看我协同的 (
{
props
.
storeTaskNum
.
myAssistNum
}
)
</
Checkbox
>
</
Space
>
</
div
>
<
div
className=
'list-content'
>
<
XMTable
rowKey=
{
(
record
)
=>
record
.
id
}
showSorterTooltip=
{
false
}
dataSource=
{
props
.
trainListData
}
columns=
{
parseColumns
()
}
pagination=
{
false
}
onChange=
{
handleChangeTable
}
bordered
size=
'middle'
scroll=
{
{
x
:
1400
}
}
className=
'train-list-table'
renderEmpty=
{
{
description
:
<
span
style=
{
{
display
:
'block'
,
paddingBottom
:
24
}
}
>
暂无数据
</
span
>,
}
}
/>
<
div
className=
'box-footer'
>
<
PageControl
current=
{
current
-
1
}
pageSize=
{
size
}
total=
{
totalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
props
.
query
,
current
:
page
+
1
,
};
props
.
onChange
(
_query
);
}
}
showSizeChanger=
{
false
}
/>
</
div
>
</
div
>
{
shareTrainTaskModal
}
{
chooseAssignorModal
}
</
div
>
);
}
export
default
withRouter
(
TrainList
);
src/modules/task-center/train-task/components/TrainList.less
0 → 100644
View file @
b427be83
.train-list-page {
.header-line {
display: flex;
justify-content: space-between;
margin-top: 16px;
margin-bottom: 12px;
.ant-radio-button-wrapper {
color: #9d9d9d;
&:first-child {
border-radius: 4px 0 0 4px;
}
&:last-child {
border-radius: 0 4px 4px 0;
}
}
.ant-radio-button-wrapper-checked {
color: #2966ff;
}
}
.train-list-table {
.train-task-name {
display: flex;
align-items: center;
cursor: pointer;
.train-cover {
width: 106px;
height: 60px;
border-radius: 2px;
margin-right: 8px;
flex-shrink: 0;
}
.train-name {
width: 188px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height: 40px;
}
}
.task-state {
* {
vertical-align: middle;
display: inline-block;
}
.status-point {
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 4px;
}
}
.operate {
display: flex;
&__item {
color: #2966ff;
cursor: pointer;
}
.split {
margin: 0 8px;
color: #bfbfbf;
}
.more-operate {
cursor: pointer;
.more-text {
color: #2966ff;
cursor: pointer;
}
}
.disabled {
color: #ccc !important;
cursor: not-allowed !important;
pointer-events: none !important;
}
}
.tip {
cursor: pointer;
color: '#bfbfbf';
margin-left: 5px;
font-weight: normal;
}
thead.ant-table-thead {
tr {
th {
padding: 10px 16px;
}
}
}
tbody {
tr {
td.ant-table-cell {
padding: 20px 16px;
color: #333;
}
&:nth-child(even) {
background: transparent;
td {
background: #fff;
}
}
&:nth-child(odd) {
background: #fafafa;
td {
background: #fafafa;
}
}
&:hover {
td {
background: #f3f6fa;
}
}
}
}
}
}
.train-list-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;
}
}
.disabled {
color: #ccc !important;
cursor: not-allowed !important;
pointer-events: none !important;
}
}
src/modules/task-center/train-task/modal/ChooseAssignorModal.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-05 17:09:36
* @LastEditors: yuananting
* @LastEditTime: 2021-08-18 16:23:22
* @Description: 新建培训任务-选择指派学员
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'react'
;
import
{
Modal
,
Tree
,
Tooltip
,
Tabs
,
Input
,
Checkbox
}
from
'antd'
;
import
User
from
'@/common/js/user'
;
import
{
DepType
}
from
'@/domains/store-domain/constants'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
import
_
from
'underscore'
;
import
'./ChooseAssignorModal.less'
;
import
$
from
'jquery'
;
import
LottieIcon
from
'@/components/LottieIcon'
;
const
{
TabPane
}
=
Tabs
;
const
{
DirectoryTree
}
=
Tree
;
const
{
Search
}
=
Input
;
function
ChooseAssignorModal
(
props
)
{
const
AssignTypeEnum
=
{
departMentTab
:
'SECTION'
,
postGrouptab
:
'POST'
,
customGroupTab
:
'CUSTOM'
,
};
const
DeptTypeEnum
=
{
departMentTab
:
[
'部门'
],
postGrouptab
:
[
'岗位'
,
'岗位组'
],
customGroupTab
:
[
'分组'
,
'分组集合'
],
};
const
[
dropDownVisible
,
setDropDownVisible
]
=
useState
(
false
);
const
[
structureData
,
setStructureData
]
=
useState
([]);
const
[
activeKey
,
setActiveKey
]
=
useState
(
'departMentTab'
);
const
[
checkedAssignorList
,
setCheckedAssignorList
]
=
useState
(
props
.
currentAssignorList
||
[]);
// 勾选的指派学员
const
[
checkedAssignorKeys
,
setCheckedAssignorKeys
]
=
useState
(
handleCheckedKeys
(
props
.
currentAssignorList
,
props
.
currentAssignorList
,
[]));
const
[
queryName
,
setQueryName
]
=
useState
(
''
);
// 搜索框内的值
const
[
departmentUserVOList
,
setDepartmentUserVOList
]
=
useState
([]);
const
[
departmentVOList
,
setDepartmentVOList
]
=
useState
([]);
const
[
subLevelDepartmentVOList
,
setSubLevelDepartmentVOList
]
=
useState
([]);
const
queryNameRef
=
useRef
(
null
);
const
timer
=
useRef
(
null
);
useEffect
(()
=>
{
queryNameRef
.
current
=
queryName
;
clearTimeout
(
timer
.
current
);
timer
.
current
=
setTimeout
(()
=>
{
if
(
!!
queryName
)
return
getCompleteOptionData
(
queryNameRef
.
current
);
},
500
);
},
[
queryName
]);
useEffect
(()
=>
{
setQueryName
(
''
);
// 切换tab时搜索置空
setDepartmentUserVOList
([]);
setDepartmentVOList
([]);
setSubLevelDepartmentVOList
([]);
setStructureData
([]);
getStructureData
();
},
[
activeKey
]);
useEffect
(()
=>
{
documentClick
();
},
[]);
function
getStructureData
()
{
const
params
=
{
depType
:
DepType
[
activeKey
],
enterpriseId
:
User
.
getEnterpriseId
(),
source
:
0
,
// 0代表来自企培
storeId
:
User
.
getStoreId
(),
userId
:
User
.
getUserId
(),
whetherCount
:
false
,
distinct
:
false
,
queryType
:
'CUSTOMER'
,
};
StoreService
.
getDepartmentUserNotPage
(
params
).
then
((
res
)
=>
{
const
{
result
=
[]
}
=
res
;
const
structureData
=
handleStructureData
(
result
.
departmentVOList
);
const
checkedKeys
=
handleCheckedKeys
(
structureData
,
checkedAssignorList
,
[]);
setStructureData
(
structureData
);
setCheckedAssignorKeys
(
checkedKeys
);
});
}
function
handleCheckedKeys
(
dataArray
,
checkedAssignorList
,
checkedKeys
)
{
dataArray
.
map
((
item
,
index
)
=>
{
if
(
checkedAssignorList
.
find
((
checkedItem
)
=>
checkedItem
.
checkedId
===
item
.
checkedId
))
{
checkedKeys
.
push
(
item
.
id
);
}
if
(
item
.
children
?.
length
>
0
)
{
handleCheckedKeys
(
item
.
children
,
checkedAssignorList
,
checkedKeys
);
}
});
return
checkedKeys
;
}
function
handleStructureData
(
dataArray
)
{
const
_dataArray
=
dataArray
.
map
((
item
,
index
)
=>
{
item
.
title
=
''
;
item
.
checkedId
=
item
.
storeCustomerId
||
item
.
id
;
item
.
checkedType
=
item
.
storeCustomerId
?
'CUSTOMER'
:
AssignTypeEnum
[
activeKey
];
item
.
checkedName
=
item
.
storeCustomerId
?
item
.
userName
:
item
.
name
;
item
.
key
=
item
.
id
;
item
.
children
=
[];
if
(
activeKey
!==
'departMentTab'
&&
item
.
depLevel
===
0
)
{
item
.
disableCheckbox
=
true
;
}
if
(
item
.
departmentUserVOList
)
{
item
.
children
=
item
.
departmentUserVOList
;
}
if
(
item
.
sonDepartmentVOList
)
{
item
.
children
=
[...
item
.
children
,
...
item
.
sonDepartmentVOList
];
}
if
(
item
.
children
.
length
>
0
)
{
handleStructureData
(
item
.
children
);
}
else
{
delete
item
.
children
;
}
return
item
;
});
return
_dataArray
;
}
function
onCheckAssignor
(
key
,
e
)
{
const
{
node
,
checked
}
=
e
;
let
_checkedAssignorList
=
[...
checkedAssignorList
];
if
(
checked
)
{
_checkedAssignorList
.
push
(
node
);
}
else
{
_checkedAssignorList
=
_checkedAssignorList
.
filter
((
item
)
=>
{
return
item
.
checkedId
!==
node
.
checkedId
;
});
}
const
_checkedAssignorKeys
=
handleCheckedKeys
(
structureData
,
_checkedAssignorList
,
[]);
setCheckedAssignorList
(
_checkedAssignorList
);
setCheckedAssignorKeys
(
_checkedAssignorKeys
);
}
function
removeCheckedAssignor
(
item
)
{
const
_checkedAssignorList
=
checkedAssignorList
.
filter
((
childItem
)
=>
childItem
.
checkedId
!==
item
.
checkedId
);
const
_checkedAssignorKeys
=
_checkedAssignorList
.
map
((
item
)
=>
item
.
id
);
setCheckedAssignorKeys
(
_checkedAssignorKeys
);
setCheckedAssignorList
(
_checkedAssignorList
);
}
function
clearCheckedAssignor
()
{
setCheckedAssignorKeys
([]);
setCheckedAssignorList
([]);
}
function
getCompleteOptionData
(
value
)
{
const
params
=
{
depType
:
DepType
[
activeKey
],
queryName
:
value
,
enterpriseId
:
User
.
getEnterpriseId
(),
source
:
0
,
//0代表来自企培
storeId
:
User
.
getStoreId
(),
userId
:
User
.
getUserId
(),
whetherCount
:
false
,
distinct
:
false
,
queryType
:
'CUSTOMER'
,
};
StoreService
.
getDepartmentUser
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
departmentUserVOList
=
[],
departmentVOList
=
[],
subLevelDepartmentVOList
=
[]
}
=
result
;
const
_departmentUserVOList
=
departmentUserVOList
.
map
((
item
)
=>
{
item
.
checkedName
=
item
.
userName
;
item
.
checkedId
=
item
.
storeCustomerId
;
item
.
checked
=
checkedAssignorList
.
find
((
checkedItem
)
=>
checkedItem
.
checkedId
===
item
.
checkedId
);
item
.
checkedType
=
'CUSTOMER'
;
return
item
;
});
const
_departmentVOList
=
departmentVOList
.
map
((
item
)
=>
{
item
.
disabled
=
activeKey
!==
'departMentTab'
;
item
.
checkedName
=
item
.
name
;
item
.
checkedId
=
item
.
id
;
item
.
checked
=
checkedAssignorList
.
find
((
checkedItem
)
=>
checkedItem
.
checkedId
===
item
.
checkedId
);
item
.
checkedType
=
AssignTypeEnum
[
activeKey
];
return
item
;
});
const
_subLevelDepartmentVOList
=
subLevelDepartmentVOList
.
map
((
item
)
=>
{
item
.
checkedName
=
item
.
name
;
item
.
checkedId
=
item
.
id
;
item
.
checked
=
checkedAssignorList
.
find
((
checkedItem
)
=>
checkedItem
.
checkedId
===
item
.
checkedId
);
item
.
checkedType
=
AssignTypeEnum
[
activeKey
];
return
item
;
});
setDepartmentUserVOList
(
_departmentUserVOList
);
setDepartmentVOList
(
_departmentVOList
);
setSubLevelDepartmentVOList
(
_subLevelDepartmentVOList
);
});
}
// 搜索空状态渲染;
function
renderEmptyContent
()
{
return
(
<
div
className=
'empty-con'
>
<
img
src=
'https://image.xiaomaiketang.com/xm/wRDrb2pJFb.png'
className=
'empty-img'
/>
<
div
className=
'empty-text'
>
暂无数据
</
div
>
</
div
>
);
}
function
handleCheckedSearchAssignor
(
e
,
type
)
{
const
{
value
,
checked
}
=
e
.
target
;
let
_departmentUserVOList
=
[...
departmentUserVOList
];
let
_departmentVOList
=
[...
departmentVOList
];
let
_subLevelDepartmentVOList
=
[...
subLevelDepartmentVOList
];
let
_checkedAssignorList
=
[...
checkedAssignorList
];
if
(
type
===
'CUSTOMER'
)
{
if
(
checked
)
{
_departmentUserVOList
=
departmentUserVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
true
;
}
return
item
;
});
_checkedAssignorList
.
push
({
...
value
,
checked
:
true
});
}
else
{
_departmentUserVOList
=
departmentUserVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
false
;
}
return
item
;
});
_checkedAssignorList
=
_checkedAssignorList
.
filter
((
item
)
=>
item
.
checkedId
!==
value
.
checkedId
);
}
setDepartmentUserVOList
(
_departmentUserVOList
);
}
if
(
type
===
'DEPART'
)
{
if
(
checked
)
{
_departmentVOList
=
departmentVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
true
;
}
return
item
;
});
_checkedAssignorList
.
push
({
...
value
,
checked
:
true
});
}
else
{
_departmentVOList
=
departmentVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
false
;
}
return
item
;
});
_checkedAssignorList
=
_checkedAssignorList
.
filter
((
item
)
=>
item
.
checkedId
!==
value
.
checkedId
);
}
setDepartmentVOList
(
_departmentVOList
);
}
if
(
type
===
'GROUP'
)
{
if
(
checked
)
{
_subLevelDepartmentVOList
=
subLevelDepartmentVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
true
;
}
return
item
;
});
_checkedAssignorList
.
push
({
...
value
,
checked
:
true
});
}
else
{
_subLevelDepartmentVOList
=
subLevelDepartmentVOList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
false
;
}
return
item
;
});
_checkedAssignorList
=
subLevelDepartmentVOList
.
filter
((
item
)
=>
item
.
checkedId
!==
value
.
checkedId
);
}
setSubLevelDepartmentVOList
(
_subLevelDepartmentVOList
);
}
const
_checkedAssignorKeys
=
handleCheckedKeys
(
structureData
,
_checkedAssignorList
,
[]);
setCheckedAssignorKeys
(
_checkedAssignorKeys
);
setCheckedAssignorList
(
_checkedAssignorList
);
}
// 弱提示渲染
function
handlePlaceHolder
()
{
let
placeholder
=
''
;
switch
(
activeKey
)
{
case
'departMentTab'
:
placeholder
=
'搜索学员、部门'
;
break
;
case
'postGrouptab'
:
placeholder
=
'搜索学员、岗位、岗位组'
;
break
;
case
'customGroupTab'
:
placeholder
=
'搜索学员、分组、分组集合'
;
break
;
default
:
break
;
}
return
placeholder
;
}
function
handleDepName
(
depArray
)
{
const
depArrayDom
=
depArray
.
map
((
item
,
index
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
;
</
span
>
);
});
return
depArrayDom
;
}
function
renderOptions
()
{
return
(
<
div
className=
'left-search-dropdown'
id=
'left-search-dropdown'
>
{
departmentUserVOList
.
length
>
0
&&
(
<
div
>
<
div
>
学员
</
div
>
{
departmentUserVOList
.
map
((
record
)
=>
{
return
(
<
Checkbox
checked=
{
record
.
checked
}
value=
{
record
}
key=
{
record
.
checkedId
}
onChange=
{
(
e
)
=>
handleCheckedSearchAssignor
(
e
,
'CUSTOMER'
)
}
>
<
div
className=
'search-result-item'
depId=
{
record
.
checkedId
}
type=
{
type
}
>
<
div
className=
'search-result-item__left'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
record
.
userName
}
/>
</
div
>
<
div
className=
'search-result-item__right'
>
<
Tooltip
title=
{
<
div
>
{
handleDepName
(
record
.
depNamesList
)
}
</
div
>
}
placement=
'top'
arrowPointAtCenter
>
{
record
.
depNamesList
.
map
((
item
,
index
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
{
index
<
record
.
depNamesList
.
length
-
1
?
';'
:
''
}
</
span
>
);
})
}
</
Tooltip
>
</
div
>
</
div
>
</
Checkbox
>
);
})
}
</
div
>
)
}
{
subLevelDepartmentVOList
.
length
>
0
&&
(
<
div
>
<
div
>
{
DeptTypeEnum
[
activeKey
][
0
]
}
</
div
>
{
subLevelDepartmentVOList
.
map
((
record
)
=>
{
return
(
<
Checkbox
checked=
{
record
.
checked
}
value=
{
record
}
key=
{
record
.
checkedId
}
onChange=
{
(
e
)
=>
handleCheckedSearchAssignor
(
e
,
'GROUP'
)
}
>
<
div
className=
'search-result-item'
depId=
{
record
.
checkedId
}
type=
{
type
}
>
<
div
className=
'search-result-item__left'
>
{
<
WWOpenDataCom
type=
'departmentName'
openid=
{
record
.
name
}
/>
}
</
div
>
</
div
>
</
Checkbox
>
);
})
}
</
div
>
)
}
{
departmentVOList
.
length
>
0
&&
(
<
div
>
<
div
>
{
activeKey
===
'departMentTab'
?
DeptTypeEnum
[
activeKey
][
0
]
:
DeptTypeEnum
[
activeKey
][
1
]
}
</
div
>
{
departmentVOList
.
map
((
record
)
=>
{
return
(
<
Checkbox
disabled=
{
record
.
disabled
}
checked=
{
record
.
checked
}
value=
{
record
}
key=
{
record
.
checkedId
}
onChange=
{
(
e
)
=>
handleCheckedSearchAssignor
(
e
,
'DEPART'
)
}
>
<
div
className=
'search-result-item'
depId=
{
record
.
checkedId
}
type=
{
type
}
>
<
div
className=
'search-result-item__left'
>
{
activeKey
===
'departMentTab'
?
<
WWOpenDataCom
type=
'departmentName'
openid=
{
record
.
name
}
/>
:
<
span
>
{
record
.
name
}
</
span
>
}
</
div
>
<
div
className=
'search-result-item__right'
>
{
activeKey
===
'postGrouptab'
&&
<
span
>
{
record
.
parentName
}
</
span
>
}
</
div
>
</
div
>
</
Checkbox
>
);
})
}
</
div
>
)
}
{
departmentUserVOList
.
length
===
0
&&
departmentVOList
.
length
===
0
&&
subLevelDepartmentVOList
.
length
===
0
&&
renderEmptyContent
()
}
</
div
>
);
}
function
documentClick
()
{
document
.
onclick
=
function
(
e
)
{
let
_con
=
$
(
'#left-search-dropdown'
);
if
(
!
_con
.
is
(
e
.
target
)
&&
_con
.
has
(
e
.
target
).
length
===
0
)
{
setDropDownVisible
(
false
);
}
};
}
return
(
<
Modal
className=
'choose-assignor-modal'
title=
'添加指派学员'
visible=
{
true
}
onCancel=
{
props
.
onClose
}
onOk=
{
()
=>
{
props
.
onConfirm
(
checkedAssignorList
);
}
}
width=
{
680
}
maskClosable=
{
false
}
>
<
div
className=
'assignor-container'
>
<
div
className=
'left-list'
>
<
Search
style=
{
{
width
:
272
}
}
placeholder=
{
handlePlaceHolder
()
}
value=
{
queryName
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
onChange=
{
(
e
)
=>
{
setQueryName
(
e
.
target
.
value
);
setDropDownVisible
(
!!
e
.
target
.
value
);
}
}
/>
{
dropDownVisible
&&
renderOptions
()
}
<
div
className=
'data-body'
>
<
Tabs
size=
{
'small'
}
onChange=
{
(
key
)
=>
setActiveKey
(
key
)
}
>
<
TabPane
key=
'departMentTab'
tab=
'部门'
></
TabPane
>
<
TabPane
key=
'postGrouptab'
tab=
'岗位组'
></
TabPane
>
<
TabPane
key=
'customGroupTab'
tab=
'自定义分组'
></
TabPane
>
</
Tabs
>
<
div
className=
'tree-con'
>
<
Choose
>
<
When
condition=
{
structureData
.
length
>
0
}
>
<
DirectoryTree
checkable
checkStrictly
showIcon=
{
false
}
treeData=
{
structureData
}
checkedKeys=
{
checkedAssignorKeys
}
onCheck=
{
(
key
,
e
)
=>
onCheckAssignor
(
key
,
e
)
}
titleRender=
{
(
nodeData
)
=>
{
return
(
<
div
className=
'node-title-div'
>
{
nodeData
.
checkedType
===
'CUSTOMER'
?
(
<
div
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
nodeData
.
checkedName
}
/>
</
span
>
</
div
>
)
:
(
<
div
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
nodeData
.
checkedName
}
/>
</
span
>
</
div
>
)
}
</
div
>
);
}
}
/>
</
When
>
<
Otherwise
>
<
LottieIcon
title=
'搜索无结果'
type=
'search'
size=
{
150
}
/>
</
Otherwise
>
</
Choose
>
</
div
>
</
div
>
</
div
>
<
div
className=
'right-list'
>
<
div
className=
'header-line'
>
<
span
className=
'tip-text'
>
已选择
</
span
>
<
span
className=
'clear-btn'
onClick=
{
clearCheckedAssignor
}
>
清空
</
span
>
</
div
>
<
div
className=
'data-body'
>
<
Choose
>
<
When
condition=
{
checkedAssignorList
.
length
>
0
}
>
{
checkedAssignorList
.
map
((
item
,
index
)
=>
{
return
(
<
div
className=
'selected-item'
>
<
span
className=
'item-title'
>
{
item
.
checkedType
===
'CUSTOMER'
?
(
<
div
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
Tooltip
title=
{
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
}
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
</
span
>
</
Tooltip
>
</
div
>
)
:
(
<
div
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
Tooltip
title=
{
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
.
checkedName
}
/>
}
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
.
checkedName
}
/>
</
span
>
</
Tooltip
>
</
div
>
)
}
</
span
>
<
span
className=
'icon iconfont clear-icon'
onClick=
{
()
=>
removeCheckedAssignor
(
item
)
}
>

</
span
>
</
div
>
);
})
}
</
When
>
<
Otherwise
>
<
LottieIcon
title=
'暂无数据'
type=
'college'
size=
{
150
}
/>
</
Otherwise
>
</
Choose
>
</
div
>
</
div
>
</
div
>
</
Modal
>
);
}
export
default
ChooseAssignorModal
;
src/modules/task-center/train-task/modal/ChooseAssignorModal.less
0 → 100644
View file @
b427be83
.choose-assignor-modal {
.assignor-container {
display: flex;
height: 417px;
.left-list {
position: relative;
width: 50%;
margin-right: 24px;
padding: 12px 0 12px 16px;
border: 1px solid #e8e8e8;
.ant-select-auto-complete .ant-select-clear {
font-size: 14px;
right: 15px;
}
.left-search-dropdown {
position: absolute;
padding: 16px;
background: #fff;
box-shadow: 0px 2px 8px 0px rgba(0, 0, 0, 0.08);
z-index: 999;
border-radius: 2px;
width: 274px;
max-height: 280px;
overflow-y: scroll;
.catalog-title {
font-size: 14px;
color: #666;
margin-bottom: 14px;
}
.search-result-item {
padding: 14px 0;
color: #333;
width: 220px;
display: flex;
justify-content: space-between;
.title-icon {
color: #999;
margin-right: 3px;
}
.search-result-item__left {
font-size: 14px;
}
.search-result-item__right {
font-size: 14px;
width: 84px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: #999;
text-align: right;
}
}
.ant-select-dropdown-menu-item-group-title {
color: #666;
font-weight: bold;
}
.ant-select-item-option-grouped {
padding-left: 12px;
}
.empty-con {
text-align: center;
.empty-img {
width: 150px;
height: 150px;
}
.empty-text {
color: #666;
}
}
}
.data-body {
.ant-tabs-nav {
margin: 0 !important;
.ant-tabs-tab {
padding: 16px 0 10px 0 !important;
font-size: 14px !important;
}
}
.lottie-icon {
margin-top: 64px;
.lottie-icon__title {
color: #666666;
}
}
.tree-con {
overflow-y: scroll;
overflow-x: hidden;
max-height: 323px;
padding-right: 16px;
.ant-tree .ant-tree-treenode {
padding: 12px 0 !important;
}
.node-title-div {
display: flex;
justify-content: space-between;
white-space: nowrap;
.title-icon {
margin-right: 6px;
color: #999999;
}
.title-name {
position: absolute;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
width: 55%;
left: 28px;
color: #666666;
}
}
.ant-tree.ant-tree-directory {
.ant-tree-treenode-selected:hover::before,
.ant-tree-treenode-selected::before {
background: #f3f6fa;
}
}
.ant-tree-switcher {
color: #999999 !important;
}
}
}
}
.right-list {
width: 50%;
border: 1px solid #e8e8e8;
.header-line {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #e8e8e8;
padding: 12px 16px;
.tip-text {
font-weight: 500;
color: #333333;
}
.clear-btn {
color: #2966ff;
cursor: pointer;
}
}
.data-body {
overflow-y: scroll;
overflow-x: hidden;
max-height: 370px;
.lottie-icon {
margin-top: 76px;
.lottie-icon__title {
color: #666666;
}
}
.selected-item {
padding: 12px 12px 12px 16px;
display: flex;
justify-content: space-between;
.item-title {
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.title-icon {
color: #999999;
margin-right: 6px;
}
.title-name {
color: #333333;
}
}
.clear-icon {
font-size: 16px;
color: #999999;
vertical-align: middle;
cursor: pointer;
}
}
}
}
}
}
src/modules/task-center/train-task/modal/ChooseCollaboratorModal.jsx
0 → 100644
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-08-12 16:27:38
* @LastEditors: yuananting
* @LastEditTime: 2021-08-17 19:10:02
* @Description: 新建培训任务-选择协同人员
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Modal
,
Input
,
Tooltip
,
List
,
Checkbox
}
from
'antd'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
'./ChooseCollaboratorModal.less'
;
import
WWOpenDataCom
from
'@/components/WWOpenDataCom'
;
import
LottieIcon
from
'@/components/LottieIcon'
;
import
_
from
'underscore'
;
const
{
Search
}
=
Input
;
function
ChooseCollaboratorModal
(
props
)
{
const
[
searchKey
,
setSearchKey
]
=
useState
(
''
);
// 搜索内容
const
[
employeeList
,
setEmployeeList
]
=
useState
([]);
// 员工列表
const
[
checkedCollaboratorList
,
setCheckedCollaboratorList
]
=
useState
(
props
.
currentCollaboratorList
||
[]);
// 勾选的协同人员
const
[
checkedCollaboratorKeys
,
setCheckedCollaboratorKeys
]
=
useState
(
props
.
currentCollaboratorList
.
map
((
item
)
=>
item
.
checkedId
)
||
[]);
const
[
allChecked
,
setAllChecked
]
=
useState
(
false
);
useEffect
(()
=>
{
getEmployeeList
();
},
[
searchKey
]);
function
getEmployeeList
()
{
const
params
=
{
current
:
1
,
size
:
999
,
nickName
:
searchKey
,
phone
:
''
,
roleCodes
:
[],
};
StoreService
.
getEmployeeList
(
params
).
then
((
res
)
=>
{
const
{
records
}
=
res
.
result
;
records
.
map
((
item
)
=>
{
item
.
checkedName
=
item
.
nickName
;
item
.
checkedId
=
item
.
id
;
item
.
checked
=
checkedCollaboratorKeys
.
includes
(
item
.
checkedId
);
return
item
;
});
const
checkedEmployeeList
=
records
.
filter
((
item
)
=>
item
.
checked
);
const
_checkedAll
=
records
.
length
===
checkedEmployeeList
.
length
;
setEmployeeList
(
records
);
setAllChecked
(
_checkedAll
);
});
}
function
renderDepItem
(
record
)
{
if
(
!
record
.
depNameList
)
{
return
<
span
>
-
</
span
>;
}
return
record
.
depNameList
.
map
((
item
,
index
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
{
index
<
record
.
depNameList
.
length
-
1
?
'、'
:
''
}
</
span
>
);
});
}
function
handleCheckedCollaborator
(
e
)
{
const
{
value
,
checked
}
=
e
.
target
;
let
_checkedCollaboratorList
=
[...
checkedCollaboratorList
];
let
_employeeList
=
[];
if
(
checked
)
{
_employeeList
=
employeeList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
true
;
}
return
item
;
});
_checkedCollaboratorList
.
push
({
...
value
,
checked
:
true
});
}
else
{
_employeeList
=
employeeList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
value
.
checkedId
)
{
item
.
checked
=
false
;
}
return
item
;
});
_checkedCollaboratorList
=
checkedCollaboratorList
.
filter
((
item
)
=>
item
.
checkedId
!==
value
.
checkedId
);
}
const
_checkedCollaboratorKeys
=
_checkedCollaboratorList
.
map
((
item
)
=>
item
.
checkedId
);
const
checkedEmployeeList
=
_employeeList
.
filter
((
item
)
=>
item
.
checked
);
const
_checkedAll
=
employeeList
.
length
===
checkedEmployeeList
.
length
;
setEmployeeList
(
_employeeList
);
setCheckedCollaboratorList
(
_checkedCollaboratorList
);
setCheckedCollaboratorKeys
(
_checkedCollaboratorKeys
);
setAllChecked
(
_checkedAll
);
}
function
removeCheckedCollaborator
(
record
)
{
const
_employeeList
=
employeeList
.
map
((
item
)
=>
{
if
(
item
.
checkedId
===
record
.
checkedId
)
{
item
.
checked
=
false
;
}
return
item
;
});
const
_checkedCollaboratorList
=
checkedCollaboratorList
.
filter
((
item
)
=>
item
.
checkedId
!==
record
.
checkedId
);
const
_checkedCollaboratorKeys
=
_checkedCollaboratorList
.
map
((
item
)
=>
item
.
checkedId
);
const
checkedEmployeeList
=
_employeeList
.
filter
((
item
)
=>
item
.
checked
);
const
_checkedAll
=
employeeList
.
length
===
checkedEmployeeList
.
length
;
setAllChecked
(
_checkedAll
);
setCheckedCollaboratorList
(
_checkedCollaboratorList
);
setCheckedCollaboratorKeys
(
_checkedCollaboratorKeys
);
setEmployeeList
(
_employeeList
);
}
function
clearCheckedCollaborator
()
{
const
_employeeList
=
employeeList
.
map
((
item
)
=>
{
item
.
checked
=
item
.
checkedId
===
props
.
createId
;
return
item
;
});
const
createrItem
=
checkedCollaboratorList
.
filter
((
item
)
=>
item
.
checkedId
===
props
.
createId
);
setEmployeeList
(
_employeeList
);
setCheckedCollaboratorList
(
createrItem
);
setCheckedCollaboratorKeys
([
props
.
createId
]);
setAllChecked
(
false
);
}
function
handleCheckedAll
(
e
)
{
let
_employeeList
=
[];
let
_checkedCollaboratorList
=
[];
if
(
e
.
target
.
checked
)
{
_employeeList
=
employeeList
.
map
((
item
)
=>
{
item
.
checked
=
true
;
return
item
;
});
const
filterList
=
employeeList
.
filter
((
item
)
=>
{
return
!
checkedCollaboratorKeys
.
includes
(
item
.
checkedId
);
});
_checkedCollaboratorList
=
checkedCollaboratorList
.
concat
([...
filterList
]);
}
else
{
_employeeList
=
employeeList
.
map
((
item
)
=>
{
item
.
checked
=
item
.
checkedId
===
props
.
createId
;
return
item
;
});
const
removeIds
=
_employeeList
.
filter
((
item
)
=>
!
item
.
checked
).
map
((
childItem
)
=>
childItem
.
checkedId
);
_checkedCollaboratorList
=
checkedCollaboratorList
.
filter
((
item
)
=>
{
return
!
removeIds
.
includes
(
item
.
checkedId
);
});
}
const
_checkedCollaboratorKeys
=
_checkedCollaboratorList
.
map
((
item
)
=>
item
.
checkedId
);
setEmployeeList
(
_employeeList
);
setCheckedCollaboratorList
(
_checkedCollaboratorList
);
setCheckedCollaboratorKeys
(
_checkedCollaboratorKeys
);
setAllChecked
(
e
.
target
.
checked
);
}
return
(
<
Modal
className=
'choose-collaborator-modal'
title=
'选择协同者'
visible=
{
true
}
onCancel=
{
props
.
onClose
}
onOk=
{
()
=>
{
props
.
onConfirm
(
checkedCollaboratorList
);
props
.
onClose
();
}
}
width=
{
680
}
maskClosable=
{
false
}
>
<
div
className=
'collaborator-container'
>
<
div
className=
'left-list'
>
<
Search
placeholder=
'搜索员工'
value=
{
searchKey
}
style=
{
{
paddingRight
:
16
}
}
onChange=
{
(
e
)
=>
setSearchKey
(
e
.
target
.
value
.
trim
())
}
onSearch=
{
getEmployeeList
}
className=
'search search-input'
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
/>
<
div
className=
'data-body'
>
<
Choose
>
<
When
condition=
{
employeeList
.
length
>
0
}
>
<
List
header=
{
<
Checkbox
checked=
{
allChecked
}
onChange=
{
handleCheckedAll
}
>
全部
</
Checkbox
>
}
dataSource=
{
employeeList
}
renderItem=
{
(
item
,
index
)
=>
(
<
List
.
Item
>
<
Checkbox
checked=
{
item
.
checked
}
value=
{
item
}
key=
{
item
.
checkedId
}
disabled=
{
item
.
checkedId
===
props
.
createId
}
onChange=
{
handleCheckedCollaborator
}
>
<
div
className=
'employee-item'
>
<
span
className=
'item-title'
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
Tooltip
title=
{
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
}
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
</
span
>
</
Tooltip
>
</
span
>
<
span
className=
'dep-info'
>
{
renderDepItem
(
item
)
}
</
span
>
</
div
>
</
Checkbox
>
</
List
.
Item
>
)
}
/>
</
When
>
<
Otherwise
>
<
LottieIcon
title=
'搜索无结果'
type=
'search'
size=
{
150
}
/>
</
Otherwise
>
</
Choose
>
</
div
>
</
div
>
<
div
className=
'right-list'
>
<
div
className=
'header-line'
>
<
span
className=
'tip-text'
>
已选择
</
span
>
<
span
className=
'clear-btn'
onClick=
{
clearCheckedCollaborator
}
>
清空
</
span
>
</
div
>
<
div
className=
'data-body'
>
{
checkedCollaboratorList
.
map
((
item
,
index
)
=>
{
return
(
<
div
className=
'selected-item'
>
<
span
className=
'item-title'
>
<
span
className=
'icon iconfont title-icon'
>

</
span
>
<
Tooltip
title=
{
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
}
>
<
span
className=
'title-name'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
item
.
checkedName
}
/>
</
span
>
</
Tooltip
>
</
span
>
<
span
className=
{
`icon iconfont clear-icon ${item.checkedId === props.createId && 'disabled'}`
}
onClick=
{
()
=>
removeCheckedCollaborator
(
item
)
}
>

</
span
>
</
div
>
);
})
}
</
div
>
</
div
>
</
div
>
</
Modal
>
);
}
export
default
ChooseCollaboratorModal
;
src/modules/task-center/train-task/modal/ChooseCollaboratorModal.less
0 → 100644
View file @
b427be83
.choose-collaborator-modal {
.collaborator-container {
display: flex;
height: 417px;
.left-list {
width: 50%;
margin-right: 24px;
padding: 12px 0 12px 16px;
border: 1px solid #e8e8e8;
.data-body {
overflow-y: scroll;
overflow-x: hidden;
max-height: 370px;
width: 288px;
.lottie-icon {
margin-top: 76px;
.lottie-icon__title {
color: #666666;
}
}
.ant-list {
.ant-list-item:hover {
background-color: #f3f6fa;
}
}
.employee-item {
display: flex;
justify-content: space-between;
.item-title {
width: 110px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.title-icon {
color: #0081f0;
margin-right: 6px;
}
.title-name {
color: #333333;
}
}
.dep-info {
width: 128px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-left: 12px;
text-align: right;
}
}
}
}
.right-list {
width: 50%;
border: 1px solid #e8e8e8;
.header-line {
display: flex;
justify-content: space-between;
border-bottom: 1px solid #e8e8e8;
padding: 12px 16px;
.tip-text {
font-weight: 500;
color: #333333;
}
.clear-btn {
color: #2966ff;
cursor: pointer;
}
}
.data-body {
overflow-y: scroll;
overflow-x: hidden;
max-height: 370px;
.selected-item {
padding: 12px 12px 12px 16px;
display: flex;
justify-content: space-between;
.item-title {
width: 80%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
.title-icon {
color: #0081f0;
margin-right: 6px;
}
.title-name {
color: #333333;
}
}
.clear-icon {
font-size: 16px;
color: #999999;
vertical-align: middle;
cursor: pointer;
&.disabled {
color: #ccc;
cursor: not-allowed;
pointer-events: none;
}
}
}
}
}
}
}
src/modules/task-center/train-task/modal/ShareTrainTaskModal.jsx
0 → 100644
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-07-20 19:12:49
* @Last Modified by: 吴文洁
* @Last Modified time: 2020-07-20 20:25:13
* @Description: 大班直播分享弹窗
*/
import
React
from
'react'
;
import
{
Modal
,
Button
,
message
}
from
'antd'
;
import
domtoimage
from
'dom-to-image'
;
import
qrcode
from
'@/libs/qrcode/qrcode.js'
;
import
User
from
'@/common/js/user'
;
import
$
from
'jquery'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
'./ShareTrainTaskModal.less'
;
const
DEFAULT_COVER
=
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
;
class
ShareTrainTaskModal
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
shareUrl
:
''
,
};
}
componentDidMount
()
{
// 获取短链接
this
.
handleConvertShortUrl
();
}
handleConvertShortUrl
=
()
=>
{
const
{
longUrl
}
=
this
.
props
.
data
;
// 发请求
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
);
const
qrcodeWrapDomDownload
=
document
.
querySelector
(
'#qrcodeWrap-dowload'
);
const
qrcodeNodeDownLoad
=
new
qrcode
({
text
:
this
.
state
.
shareUrl
,
size
:
196
,
});
qrcodeWrapDomDownload
.
appendChild
(
qrcodeNodeDownLoad
);
}
);
});
};
componentWillUnmount
()
{
// 页面销毁之前清空定时器
clearTimeout
(
this
.
timer
);
}
// 下载海报
handleDownloadPoster
=
()
=>
{
this
.
setState
(
{
showImg
:
true
,
time
:
new
Date
().
valueOf
(),
},
()
=>
{
this
.
setState
({
time
:
new
Date
().
valueOf
()
},
()
=>
{
let
node
=
document
.
getElementById
(
'poster-dowload'
);
domtoimage
.
toPng
(
node
).
then
((
imgData
)
=>
{
const
download
=
document
.
createElement
(
'a'
);
const
{
planName
}
=
this
.
props
.
data
;
$
(
download
).
attr
(
'href'
,
imgData
).
attr
(
'download'
,
`
${
planName
}
.png`
).
get
(
0
).
click
();
});
});
}
);
};
// 复制分享链接
handleCopy
=
()
=>
{
const
textContent
=
document
.
getElementById
(
'shareUrl'
).
innerText
;
window
.
copyText
(
textContent
);
message
.
success
(
'复制成功!'
);
};
render
()
{
const
{
data
}
=
this
.
props
;
const
{
planName
,
coverUrl
=
DEFAULT_COVER
}
=
data
;
const
{
shareUrl
,
showImg
,
time
}
=
this
.
state
;
return
(
<
Modal
title=
{
'分享培训任务'
}
width=
{
680
}
visible=
{
true
}
footer=
{
null
}
maskClosable=
{
false
}
closeIcon=
{
<
span
className=
'icon iconfont modal-close-icon'
>

</
span
>
}
className=
'share-task-modal'
onCancel=
{
this
.
props
.
close
}
>
<
div
className=
'left'
>
<
div
id=
'poster'
>
<
div
className=
'store-name'
>
<
span
className=
'text'
>
{
User
.
getStoreName
()
}
</
span
>
</
div
>
<
div
className=
'course-name-title'
>
邀请你参与培训:
</
div
>
<
div
className=
'live-couse-name'
>
{
planName
}
</
div
>
<
Choose
>
<
When
condition=
{
showImg
}
>
<
img
crossOrigin=
'*'
src=
{
coverUrl
+
`?=${time}`
}
className=
'course-cover'
alt=
''
/>
</
When
>
<
Otherwise
>
<
img
src=
{
coverUrl
+
`?=${time}`
}
className=
'course-cover'
alt=
''
/>
</
Otherwise
>
</
Choose
>
<
div
className=
'qrcode-wrap'
>
<
div
className=
'qrcode-wrap__left'
>
<
div
className=
'text'
>
长按识别二维码进入观看
</
div
>
<
img
className=
'finger'
src=
'https://image.xiaomaiketang.com/xm/thpkWDwJsC.png'
alt=
''
/>
</
div
>
<
div
className=
'qrcode-wrap__right'
id=
'qrcodeWrap'
></
div
>
</
div
>
</
div
>
<
div
id=
'poster-dowload'
>
<
div
className=
'store-name'
>
<
span
className=
'text'
>
{
User
.
getStoreName
()
}
</
span
>
</
div
>
<
div
className=
'course-name-title'
>
邀请你参与培训:
</
div
>
<
div
className=
'live-couse-name'
>
{
planName
}
</
div
>
<
Choose
>
<
When
condition=
{
showImg
}
>
<
img
crossOrigin=
'*'
src=
{
coverUrl
+
`?=${time}`
}
className=
'course-cover'
alt=
''
/>
</
When
>
<
Otherwise
>
<
img
src=
{
coverUrl
+
`?=${time}`
}
className=
'course-cover'
alt=
''
/>
</
Otherwise
>
</
Choose
>
<
div
className=
'qrcode-wrap'
>
<
div
className=
'qrcode-wrap__left'
>
<
div
className=
'text'
>
长按识别二维码进入观看
</
div
>
<
img
className=
'finger'
src=
'https://image.xiaomaiketang.com/xm/thpkWDwJsC.png'
alt=
''
/>
</
div
>
<
div
className=
'qrcode-wrap__right'
id=
'qrcodeWrap-dowload'
></
div
>
</
div
>
</
div
>
</
div
>
<
div
className=
'right'
>
<
div
className=
'share-poster right__item'
>
<
div
className=
'title'
>
① 海报分享
</
div
>
<
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
>
<
div
className=
'content url-content'
>
<
div
className=
'share-url'
id=
'shareUrl'
>
{
shareUrl
}
</
div
>
<
Button
type=
'primary'
onClick=
{
this
.
handleCopy
}
>
复制
</
Button
>
</
div
>
</
div
>
</
div
>
</
Modal
>
);
}
}
export
default
ShareTrainTaskModal
;
src/modules/task-center/train-task/modal/ShareTrainTaskModal.less
0 → 100644
View file @
b427be83
.share-task-modal {
.ant-modal-body {
display: flex;
height: 510px !important;
overflow: hidden !important;
.left {
width: 303px;
margin: 0 32px 0 16px;
box-shadow: 0px 2px 10px 0px rgba(0, 0, 0, 0.05);
border-radius: 12px;
#poster {
background: #fff;
margin: 0;
padding: 20px;
margin-bottom: 140px;
.course-name-title {
font-size: 14px;
color: #333;
line-height: 20px;
margin-bottom: 4px;
}
.live-couse-name {
font-size: 16px;
color: #333333;
font-weight: 600;
}
.course-name {
color: #333;
font-size: 16px;
font-weight: 600;
line-height: 20px;
}
.course-cover {
width: 263px;
height: 143px;
border-radius: 6px;
margin-top: 8px;
}
.qrcode-wrap {
padding: 0 16px;
display: flex;
align-items: center;
margin: 24px 0 16px 0;
&__left {
width: 98px;
text-align: center;
margin-right: 22px;
.text {
line-height: 20px;
}
.finger {
width: 40px;
height: 40px;
margin-top: 8px;
}
}
&__right {
width: 110px;
height: 110px;
padding: 6px;
}
}
.store-name {
// padding: 8px 16px;
display: flex;
align-items: center;
margin-bottom: 8px;
.text {
font-size: 12px;
color: #999;
font-size: 14px;
line-height: 20px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
}
}
#poster-dowload {
background: #fff;
margin: 0;
padding: 40px;
width: 606px;
.course-name-title {
font-size: 28px;
color: #333;
line-height: 40px;
margin-bottom: 8px;
}
.live-couse-name {
font-size: 32px;
color: #333333;
font-weight: 600;
}
.course-name {
color: #333;
font-size: 32px;
font-weight: 600;
line-height: 40px;
}
.course-cover {
width: 526px;
height: 286px;
border-radius: 6px;
margin-top: 16px;
}
.qrcode-wrap {
padding: 0 32px;
display: flex;
align-items: center;
margin: 48px 0 32px 0;
&__left {
width: 196px;
text-align: center;
margin-right: 44px;
.text {
line-height: 40px;
}
.finger {
width: 80px;
height: 80px;
margin-top: 16px;
}
}
&__right {
width: 220px;
height: 220px;
padding: 12px;
}
}
.store-name {
// padding: 8px 16px;
display: flex;
align-items: center;
margin-bottom: 16px;
.text {
font-size: 12px;
color: #999;
font-size: 28px;
line-height: 40px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
}
}
}
.right {
.title {
color: #333;
font-weight: 500;
}
.sub-title {
color: #999;
margin-top: 16px;
}
.content {
display: flex;
align-items: center;
margin-top: 8px;
.share-url {
width: 212px;
overflow: hidden;
height: 28px;
line-height: 28px;
border-radius: 4px 0 0 4px;
padding-left: 12px;
white-space: nowrap;
color: #999999;
background: #efefef;
}
.ant-btn {
margin-left: -2px;
}
}
.url-content {
position: relative;
&:after {
content: '';
width: 12px;
height: 22px;
background: #efefef;
position: absolute;
right: 71px;
}
}
.share-poster {
margin-bottom: 40px;
.content {
color: #2966ff;
cursor: pointer;
}
}
}
}
}
src/modules/teach-tool/components/CourseCategoryManage.jsx
View file @
b427be83
...
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-02-23 18:28:50
* @LastEditors: wufan
* @LastEditTime: 2021-0
7-28 16:20:05
* @LastEditTime: 2021-0
9-03 10:36:33
* @Description: 助学工具-课程分类
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -566,7 +566,7 @@ class CourseCategoryManage extends Component {
新增一级分类
</
Button
>
<
div
className=
'show-tips'
style=
{
{
marginTop
:
'12px'
,
width
:
'900px'
}
}
>
<
ShowTips
message=
'为方便管理,该分类用于课程、
培训计划、
题库、知识库等模块,改动将同步各模块更新'
/>
<
ShowTips
message=
'为方便管理,该分类用于课程、题库、知识库等模块,改动将同步各模块更新'
/>
</
div
>
<
div
className=
'course-category-tree'
>
{
...
...
src/modules/teach-tool/examination-manager/SelectPaperModal.tsx
View file @
b427be83
...
...
@@ -2,43 +2,50 @@
* @Author: yuananting
* @Date: 2021-06-16 10:14:37
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-27 14:04:03
* @LastEditTime: 2021-0
8-18 17:40:48
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useRef
,
useEffect
,
useContext
}
from
'react'
import
React
,
{
useState
,
useRef
,
useEffect
}
from
'react'
;
import
{
message
,
Modal
}
from
'antd'
;
import
{
withRouter
}
from
'react-router-dom'
;
import
PaperContent
from
'../paper-manage/PaperContent'
import
PaperContent
from
'../paper-manage/PaperContent'
;
import
'./AddExam.less'
;
import
user
from
'@/common/js/user'
;
function
SelectPaperModal
(
props
:
any
)
{
const
[
item
,
setItem
]
=
useState
(
props
.
paperInfo
);
const
itemRef
=
useRef
({});
const
[
item
,
setItem
]
=
useState
(
props
.
paperInfo
);
const
itemRef
=
useRef
({})
useEffect
(()
=>
{
itemRef
.
current
=
item
;
},
[
item
]);
useEffect
(()
=>
{
itemRef
.
current
=
item
},
[
item
])
return
<
Modal
maskClosable=
{
false
}
width=
{
1080
}
title=
"选择试卷"
visible=
{
true
}
centered=
{
true
}
onOk=
{
()
=>
{
props
.
onSelect
(
itemRef
.
current
);
props
.
close
();
}
return
(
<
Modal
maskClosable=
{
false
}
width=
{
1080
}
title=
'选择试卷'
visible=
{
true
}
centered=
{
true
}
onOk=
{
()
=>
{
if
(
Object
.
keys
(
itemRef
.
current
).
length
<
2
)
{
// 培训任务中试卷对象默认长度为0,考试中试卷对象默认长度为1
return
message
.
warning
(
'请选择试卷'
);
}
onCancel=
{
()
=>
{
props
.
close
()
}
}
>
<
PaperContent
paperId=
{
item
.
paperId
}
onSelect=
{
(
item
:
any
)
=>
{
setItem
(
item
)
}
}
type=
'modal-select'
></
PaperContent
>
</
Modal
>
props
.
onSelect
(
itemRef
.
current
);
props
.
close
();
}
}
onCancel=
{
()
=>
{
props
.
close
();
}
}
>
<
PaperContent
paperId=
{
item
.
paperId
}
onSelect=
{
(
item
:
any
)
=>
{
setItem
(
item
);
}
}
type=
'modal-select'
></
PaperContent
>
</
Modal
>
);
}
export
default
withRouter
(
SelectPaperModal
);
\ No newline at end of file
export
default
withRouter
(
SelectPaperModal
);
src/modules/teach-tool/examination-manager/TestDetailPage.jsx
View file @
b427be83
...
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-04-07 16:10:21
* @LastEditors: wufan
* @LastEditTime: 2021-0
4-26 10:21:19
* @LastEditTime: 2021-0
8-10 14:19:22
* @Description: 助学工具-考试-考试结果
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -18,6 +18,7 @@ import Breadcrumbs from '@/components/Breadcrumbs';
function
TestDetailPage
(
props
)
{
const
examId
=
props
.
match
.
params
.
testId
.
replace
(
/
\?
.+/
,
''
);
const
paperId
=
window
.
getParameterByName
(
'paperId'
);
const
fromTrainingTask
=
window
.
getParameterByName
(
'fromTrainingTask'
);
// 是否来自培训任务
const
userId
=
window
.
getParameterByName
(
'userId'
);
const
[
examDetail
,
setExamDetail
]
=
useState
({
answerAnalysis
:
''
,
...
...
@@ -41,6 +42,7 @@ function TestDetailPage(props) {
const
[
questionList
,
setQuestionList
]
=
useState
([]);
// 试卷题目列表
const
[
userAnswerList
,
setUserAnswerList
]
=
useState
([]);
// 用户答案列表
const
[
isScrollShow
,
setIsScrollShow
]
=
useState
(
false
);
// 是否展示回到顶部按钮
const
[
isShowErrorPage
,
setIsShowErrorPage
]
=
useState
(
false
);
// 是否展示异常提示页面
const
{
answerAnalysis
,
resultContent
,
examName
,
totalScore
,
totalQuestionCount
,
passScore
,
examDuration
,
userExamDuration
,
userScore
,
userCorrectQuestion
}
=
examDetail
;
...
...
@@ -211,16 +213,20 @@ function TestDetailPage(props) {
});
return
(
<
div
className=
'exam-result-page page'
>
<
Breadcrumbs
navList=
{
'答题详情'
}
goBack=
{
props
.
history
.
goBack
}
/>
<
div
className=
{
`${fromTrainingTask ? 'exam-result-page' :'exam-result-page page'}`
}
>
{
fromTrainingTask
?
null
:
<
Breadcrumbs
navList=
{
'答题详情'
}
goBack=
{
props
.
history
.
goBack
}
/>
}
<
div
className=
'center'
>
<
div
className=
'box'
>
<
img
className=
"header-img"
src=
"https://image.xiaomaiketang.com/xm/6Kt6PkJcWa.png"
/>
<
div
className=
'box-content'
>
<
div
className=
'exam-head'
style=
{
{
padding
:
examName
.
length
>
20
?
'8px 0 14px'
:
'
1
6px 0 29px'
,
padding
:
examName
.
length
>
20
?
'8px 0 14px'
:
'
2
6px 0 29px'
,
}
}
>
<
div
className=
{
`exam-name ${examName.length > 20 ? 'many' : 'few'}`
}
>
{
examName
}
</
div
>
</
div
>
...
...
src/modules/teach-tool/examination-manager/TestDetailPage.less
View file @
b427be83
...
...
@@ -19,6 +19,14 @@
}
}
.box {
position: relative;
.header-img {
height: 180px;
width: calc(100vw - 450px);
position: absolute;
left: 50%;
transform: translateX(-50%);
}
.box-content {
position: relative;
width: 840px;
...
...
@@ -40,6 +48,7 @@
.few {
font-size: 25px;
line-height: 36px;
color: #fff;
}
}
.empty-result {
...
...
src/routes/config/mainRoutes.tsx
View file @
b427be83
/*
* @Author: 吴文洁
* @Date: 2020-04-29 10:26:32
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
8-11 20:27:02
* @LastEditors:
wufan
* @LastEditTime: 2021-0
9-03 10:33:05
* @Description: 内容线路由配置
*/
import
Home
from
'@/modules/home/Home'
;
...
...
@@ -23,19 +23,21 @@ import AddGraphicsCoursePage from '@/modules/course-manage/graphics-course/AddGr
import
AddOfflineCoursePage
from
'@/modules/course-manage/offline-course/AddOfflineCourse'
;
// 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'
import
PlanPage
from
'@/modules/plan-manage/PlanPage'
import
AddPlanPage
from
'@/modules/plan-manage/AddPlan'
import
LearningDataPage
from
'@/modules/plan-manage/LearningData'
import
StoreInfoPage
from
'@/modules/store-manage/StoreInfo'
import
CourseCategoryManage
from
'@/modules/teach-tool/components/CourseCategoryManage'
import
QuestionManageIndex
from
'@/modules/teach-tool/question-manage/Index'
import
PaperManageIndex
from
'@/modules/teach-tool/paper-manage/Index'
import
ExaminationManagerIndex
from
'@/modules/teach-tool/examination-manager/Index'
import
ExaminationManagerTestDetail
from
'@/modules/teach-tool/examination-manager/TestDetailPage'
import
KnowledgeBase
from
'@/modules/knowledge-base/index'
import
CollegeInfoPage
from
'@/modules/college-manage/CollegeInfoPage'
import
ResourceDisk
from
'@/modules/resource-disk'
;
import
SwitchRoute
from
'@/modules/root/SwitchRoute'
;
import
PlanPage
from
'@/modules/plan-manage/PlanPage'
;
import
AddPlanPage
from
'@/modules/plan-manage/AddPlan'
;
import
LearningDataPage
from
'@/modules/plan-manage/LearningData'
;
import
StoreInfoPage
from
'@/modules/store-manage/StoreInfo'
;
import
CourseCategoryManage
from
'@/modules/teach-tool/components/CourseCategoryManage'
;
import
QuestionManageIndex
from
'@/modules/teach-tool/question-manage/Index'
;
import
PaperManageIndex
from
'@/modules/teach-tool/paper-manage/Index'
;
import
ExaminationManagerIndex
from
'@/modules/teach-tool/examination-manager/Index'
;
import
ExaminationManagerTestDetail
from
'@/modules/teach-tool/examination-manager/TestDetailPage'
;
import
KnowledgeBase
from
'@/modules/knowledge-base/index'
;
import
CollegeInfoPage
from
'@/modules/college-manage/CollegeInfoPage'
;
import
TrainTaskPage
from
'@/modules/task-center/train-task/TrainTaskPage'
;
import
AddTrainTask
from
'@/modules/task-center/train-task/AddTrainTask'
;
const
mainRoutes
=
[
{
...
...
@@ -161,6 +163,16 @@ const mainRoutes = [
name
:
'培训计划'
,
},
{
path
:
'/train-task'
,
component
:
TrainTaskPage
,
name
:
'培训任务'
,
},
{
path
:
'/create-train-task'
,
component
:
AddTrainTask
,
name
:
'创建培训任务'
,
},
{
path
:
'/create-plan'
,
component
:
AddPlanPage
,
name
:
'创建线上课'
,
...
...
@@ -180,6 +192,6 @@ const mainRoutes = [
component
:
LearningDataPage
,
name
:
'学习数据'
,
},
]
]
;
export
default
mainRoutes
export
default
mainRoutes
;
src/routes/config/menuList.tsx
View file @
b427be83
/*
* @Author: yuananting
* @Date: 2021-02-21 15:53:31
* @LastEditors:
wufan
* @LastEditTime: 2021-07-
05 10:29:23
* @LastEditors:
yuananting
* @LastEditTime: 2021-07-
28 11:29:17
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
...
...
@@ -44,17 +44,18 @@ export const menuList: any = [
},
],
},
{
groupName
:
'
培训管理
'
,
groupName
:
'
任务中心
'
,
groupCode
:
'TrainManage'
,
icon
:
''
,
img
:
'https://image.xiaomaiketang.com/xm/Yy6pZ6G6kS.png'
,
selectImg
:
'https://image.xiaomaiketang.com/xm/Z8G6NMQhaH.png'
,
children
:
[
{
groupName
:
'培训
计划
'
,
groupName
:
'培训
任务
'
,
groupCode
:
'TrainPlan'
,
link
:
'/
plan
'
,
link
:
'/
train-task
'
,
},
],
},
...
...
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