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
5314960e
Commit
5314960e
authored
Aug 16, 2021
by
yuananting
Browse files
Options
Browse Files
Download
Plain Diff
fix:解决合并代码的冲突
parents
ce5b164f
571796c7
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
768 additions
and
171 deletions
+768
-171
src/common/less/icon-font.less
+3
-3
src/domains/basic-domain/constants.ts
+20
-20
src/domains/course-domain/constants.ts
+15
-18
src/h5.html
+2
-2
src/index.html
+2
-2
src/modules/knowledge-base/components/KnowledgeBaseList.jsx
+0
-0
src/modules/knowledge-base/modal/VideoList.jsx
+50
-73
src/modules/task-center/data-center/Index.tsx
+14
-5
src/modules/task-center/data-center/components/DataAnalysic.tsx
+63
-0
src/modules/task-center/data-center/components/ExamData.tsx
+321
-0
src/modules/task-center/data-center/components/ExamTable.tsx
+12
-4
src/modules/task-center/data-center/components/LeftStageList.jsx
+2
-2
src/modules/task-center/data-center/components/StudyTable.tsx
+2
-3
src/modules/task-center/data-center/components/UserData.tsx
+0
-0
src/modules/task-center/data-center/components/dataAnalysic.less
+22
-0
src/modules/task-center/data-center/components/userData.less
+90
-0
src/modules/task-center/train-task/components/RelatedExamDrawer.jsx
+2
-2
src/modules/task-center/train-task/modal/ChooseAssignorModal.jsx
+94
-35
src/modules/task-center/train-task/modal/ChooseAssignorModal.less
+54
-2
No files found.
src/common/less/icon-font.less
View file @
5314960e
@font-face {
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_
2digpsfgq8l.woff2?t=1628853864698
') format('woff2'),
src: url('//at.alicdn.com/t/font_2223403_
0b87tvtysw45.woff2?t=1629025918841
') format('woff2'),
url('//at.alicdn.com/t/font_2223403_2digpsfgq8l.woff?t=1628853864698
') format('woff'),
url('//at.alicdn.com/t/font_2223403_0b87tvtysw45.woff?t=1629025918841
') format('woff'),
url('//at.alicdn.com/t/font_2223403_2digpsfgq8l.ttf?t=1628853864698
') format('truetype');
url('//at.alicdn.com/t/font_2223403_0b87tvtysw45.ttf?t=1629025918841
') format('truetype');
}
}
.iconfont {
.iconfont {
font-family: 'iconfont' !important;
font-family: 'iconfont' !important;
...
...
src/domains/basic-domain/constants.ts
View file @
5314960e
/*
/*
* @Author: 陈剑宇
* @Author: 陈剑宇
* @Date: 2020-05-07 14:43:01
* @Date: 2020-05-07 14:43:01
* @LastEditTime: 2021-08-
09 15:52:49
* @LastEditTime: 2021-08-
16 16:39:13
* @LastEditors:
wufan
* @LastEditors:
yuananting
* @Description:
* @Description:
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
* @FilePath: /wheat-web-demo/src/domains/basic-domain/constants.ts
*/
*/
import
{
MapInterface
}
from
'@/domains/basic-domain/interface'
import
{
MapInterface
}
from
'@/domains/basic-domain/interface'
;
import
{
path
,
live
}
from
'@/domains/brand/constants'
import
{
path
,
live
}
from
'@/domains/brand/constants'
;
// 默认是 dev 环境
// 默认是 dev 环境
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'dev'
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'dev'
;
console
.
log
(
'process.env.DEPLOY_ENV'
,
process
.
env
,
ENV
,
'hjkkkk'
)
console
.
log
(
'process.env.DEPLOY_ENV'
,
process
.
env
,
ENV
,
'hjkkkk'
);
console
.
log
(
'process.env.DEPLOY_ENV'
,
process
);
const
BASIC_HOST_MAP
:
MapInterface
=
{
const
BASIC_HOST_MAP
:
MapInterface
=
{
dev
:
'https://dev-heimdall.xiaomai5.com/'
,
dev
:
'https://dev-heimdall.xiaomai5.com/'
,
dev1
:
'https://dev-heimdall.xiaomai5.com/'
,
dev1
:
'https://dev-heimdall.xiaomai5.com/'
,
rc
:
'https://rc-heimdall.xiaomai5.com/'
,
rc
:
'https://rc-heimdall.xiaomai5.com/'
,
gray
:
'https://gray-heimdall.xiaomai5.com/'
,
gray
:
'https://gray-heimdall.xiaomai5.com/'
,
prod
:
'https://gateway.xiaomai5.com/'
,
prod
:
'https://gateway.xiaomai5.com/'
,
}
}
;
const
PATH_MAP
:
MapInterface
=
{
const
PATH_MAP
:
MapInterface
=
{
dev
:
'https://dev.xiaomai5.com/xiaomai-cloud-class-web/h5.html'
,
dev
:
'https://dev.xiaomai5.com/xiaomai-cloud-class-web/h5.html'
,
dev1
:
'https://dev.xiaomai5.com/dev1/xiaomai-cloud-class-web/h5.html'
,
dev1
:
'https://dev.xiaomai5.com/dev1/xiaomai-cloud-class-web/h5.html'
,
rc
:
'https://rc.xiaomai5.com/xiaomai-cloud-class-web/h5.html'
,
rc
:
'https://rc.xiaomai5.com/xiaomai-cloud-class-web/h5.html'
,
gray
:
path
+
'/gray/h5.html'
,
gray
:
path
+
'/gray/h5.html'
,
prod
:
path
+
'/h5.html'
,
prod
:
path
+
'/h5.html'
,
}
}
;
export
const
YZ_APPId
=
"yozoqvpO2Hvz8346"
;
export
const
YZ_APPId
=
'yozoqvpO2Hvz8346'
;
export
const
YZ_PREVIEW_URL
:
string
=
'http://eic.yozocloud.cn/api/view/file'
export
const
YZ_PREVIEW_URL
:
string
=
'http://eic.yozocloud.cn/api/view/file'
;
export
const
OFFICE_PREVIEW_URL
:
string
=
'https://view.officeapps.live.com/op/view.aspx'
export
const
OFFICE_PREVIEW_URL
:
string
=
'https://view.officeapps.live.com/op/view.aspx'
;
// axios headers config
// axios headers config
export
const
TIME_OUT
:
number
=
20000
export
const
TIME_OUT
:
number
=
20000
;
export
const
USER_TYPE
:
string
=
'B'
export
const
USER_TYPE
:
string
=
'B'
;
export
const
PROJECT
=
'xmzj-web-b'
export
const
PROJECT
=
'xmzj-web-b'
;
export
const
VERSION
=
'5.4.8'
export
const
VERSION
=
'5.4.8'
;
export
const
PREFIX
=
'cloud-class'
export
const
PREFIX
=
'cloud-class'
;
export
const
USER_PREFIX
=
'store-live'
export
const
USER_PREFIX
=
'store-live'
;
// host
// host
export
const
BASIC_HOST
:
string
=
BASIC_HOST_MAP
[
ENV
]
export
const
BASIC_HOST
:
string
=
BASIC_HOST_MAP
[
ENV
];
export
const
PATH
:
string
=
PATH_MAP
[
ENV
]
export
const
PATH
:
string
=
PATH_MAP
[
ENV
];
src/domains/course-domain/constants.ts
View file @
5314960e
/*
/*
* @Author: 吴文洁
* @Author: 吴文洁
* @Date: 2020-08-20 09:21:40
* @Date: 2020-08-20 09:21:40
* @LastEditors:
Please set LastEditors
* @LastEditors:
yuananting
* @LastEditTime: 2021-08-1
1 22:50:48
* @LastEditTime: 2021-08-1
6 16:38:55
* @Description:
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
* @Copyright: 杭州杰竞科技有限公司 版权所有
*/
*/
import
{
MapInterface
}
from
'@/domains/basic-domain/interface'
import
{
MapInterface
}
from
'@/domains/basic-domain/interface'
;
import
{
path
,
live
}
from
'@/domains/brand/constants'
import
{
path
,
live
}
from
'@/domains/brand/constants'
;
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'dev'
;
const
ENV
:
string
=
process
.
env
.
DEPLOY_ENV
||
'dev'
;
const
appIdMap
:
MapInterface
=
{
const
appIdMap
:
MapInterface
=
{
dev
:
'wx3ea60e78ddfa277e'
,
dev
:
'wx3ea60e78ddfa277e'
,
dev1
:
'wx3ea60e78ddfa277e'
,
dev1
:
'wx3ea60e78ddfa277e'
,
rc
:
'wx5c5a1fb71ecab7bc'
,
rc
:
'wx5c5a1fb71ecab7bc'
,
gray
:
"wx3dda02036493ada6"
,
// 小麦校讯通
gray
:
'wx3dda02036493ada6'
,
// 小麦校讯通
prod
:
'wx3dda02036493ada6'
,
prod
:
'wx3dda02036493ada6'
,
}
}
;
const
shareUrlMap
:
MapInterface
=
{
const
shareUrlMap
:
MapInterface
=
{
'dev'
:
'https://dev.xiaomai5.com/share/show?appid='
,
dev
:
'https://dev.xiaomai5.com/share/show?appid='
,
'dev1'
:
'https://dev.xiaomai5.com/share/show?appid='
,
dev1
:
'https://dev.xiaomai5.com/share/show?appid='
,
'rc'
:
'https://rc.xiaomai5.com/share/show?appid='
,
rc
:
'https://rc.xiaomai5.com/share/show?appid='
,
'prod'
:
'https://prod.xiaomai5.com/share/show?appid='
,
prod
:
'https://prod.xiaomai5.com/share/show?appid='
,
'gray'
:
'https://prod.xiaomai5.com/share/show?appid='
,
gray
:
'https://prod.xiaomai5.com/share/show?appid='
,
}
}
;
const
LIVE_SHARE_MAP
:
MapInterface
=
{
const
LIVE_SHARE_MAP
:
MapInterface
=
{
dev
:
'https://dev.xiaomai5.com/store-live/index.html#/'
,
dev
:
'https://dev.xiaomai5.com/store-live/index.html#/'
,
dev1
:
'https://dev.xiaomai5.com/dev1/store-live/index.html#/'
,
dev1
:
'https://dev.xiaomai5.com/dev1/store-live/index.html#/'
,
rc
:
'https://rc.xiaomai5.com/store-live/index.html#/'
,
rc
:
'https://rc.xiaomai5.com/store-live/index.html#/'
,
gray
:
live
+
'/gray/index.html#/'
,
gray
:
live
+
'/gray/index.html#/'
,
prod
:
live
+
'/index.html#/'
,
prod
:
live
+
'/index.html#/'
,
}
};
export
const
appId
:
string
=
appIdMap
[
ENV
];
export
const
appId
:
string
=
appIdMap
[
ENV
];
export
const
shareUrl
:
string
=
shareUrlMap
[
ENV
];
export
const
shareUrl
:
string
=
shareUrlMap
[
ENV
];
...
...
src/h5.html
View file @
5314960e
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditors: wufan
* @LastEditTime: 2021-08-1
3 19:25:12
* @LastEditTime: 2021-08-1
5 19:12:48
* @Description:
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
-->
...
@@ -25,7 +25,7 @@
...
@@ -25,7 +25,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
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=
"manifest"
href=
"%PUBLIC_URL%/manifest.json"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
2digpsfgq8l
.css"
>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
0b87tvtysw45
.css"
>
<!--
<!--
Notice the use of %PUBLIC_URL% in the tags above.
Notice the use of %PUBLIC_URL% in the tags above.
...
...
src/index.html
View file @
5314960e
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* @Author: 吴文洁
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @Date: 2020-08-24 12:20:57
* @LastEditors: wufan
* @LastEditors: wufan
* @LastEditTime: 2021-08-1
3 19:25:18
* @LastEditTime: 2021-08-1
5 19:12:55
* @Description:
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
-->
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
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=
"manifest"
href=
"%PUBLIC_URL%/manifest.json"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
2digpsfgq8l
.css"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
0b87tvtysw45
.css"
/>
<!--
<!--
Notice the use of %PUBLIC_URL% in the tags above.
Notice the use of %PUBLIC_URL% in the tags above.
...
...
src/modules/knowledge-base/components/KnowledgeBaseList.jsx
View file @
5314960e
This diff is collapsed.
Click to expand it.
src/modules/knowledge-base/modal/VideoList.jsx
View file @
5314960e
...
@@ -2,29 +2,30 @@
...
@@ -2,29 +2,30 @@
* @Description:
* @Description:
* @Author: zangsuyun
* @Author: zangsuyun
* @Date: 2021-03-13 11:48:24
* @Date: 2021-03-13 11:48:24
* @LastEditors:
wufan
* @LastEditors:
yuananting
* @LastEditTime: 2021-08-
09 15:53:08
* @LastEditTime: 2021-08-
16 16:38:20
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
* @Copyright: © 2020 杭州杰竞科技有限公司 版权所有
*/
*/
import
React
from
"react"
;
import
React
from
'react'
;
import
{
Table
,
Modal
,
message
,
Tooltip
,
Switch
,
Dropdown
}
from
"antd"
;
import
{
Table
,
Modal
,
message
,
Tooltip
,
Switch
,
Dropdown
}
from
'antd'
;
import
{
PageControl
}
from
"@/components"
;
import
{
PageControl
}
from
'@/components'
;
import
_
from
"underscore"
;
import
_
from
'underscore'
;
import
{
LIVE_SHARE_MAP
}
from
"@/common/constants/academic/cloudClass"
;
import
{
LIVE_SHARE_MAP
}
from
'@/common/constants/academic/cloudClass'
;
import
{
appId
,
shareUrl
,
LIVE_SHARE
}
from
"@/domains/course-domain/constants"
;
import
{
appId
,
shareUrl
,
LIVE_SHARE
}
from
'@/domains/course-domain/constants'
;
import
TableSelectedData
from
"@/components/TableSelectedData"
;
import
TableSelectedData
from
'@/components/TableSelectedData'
;
import
"./LiveList.less"
;
import
'./LiveList.less'
;
import
CourseService
from
"@/domains/course-domain/CourseService"
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
User
from
"@/common/js/user"
;
import
User
from
'@/common/js/user'
;
const
ENV
=
process
.
env
.
DEPLOY_ENV
||
'dev'
;
class
VideoList
extends
React
.
Component
{
class
VideoList
extends
React
.
Component
{
constructor
(
props
)
{
constructor
(
props
)
{
super
(
props
);
super
(
props
);
this
.
state
=
{
this
.
state
=
{
id
:
""
,
// 线上课ID
id
:
''
,
// 线上课ID
studentIds
:
[],
studentIds
:
[],
selectedRowKeys
:
[],
selectedRowKeys
:
[],
query
:
{
query
:
{
...
@@ -40,8 +41,7 @@ class VideoList extends React.Component {
...
@@ -40,8 +41,7 @@ class VideoList extends React.Component {
componentDidUpdate
(
prevProps
,
prevState
)
{
componentDidUpdate
(
prevProps
,
prevState
)
{
//必须写在if里面并且重新进行一次this.props !== prevProps的判断
//必须写在if里面并且重新进行一次this.props !== prevProps的判断
if
(
if
(
((
this
.
props
.
courseName
||
this
.
props
.
courseType
)
&&
((
this
.
props
.
courseName
||
this
.
props
.
courseType
)
&&
this
.
props
.
courseName
!==
prevProps
.
courseName
)
||
this
.
props
.
courseName
!==
prevProps
.
courseName
)
||
this
.
props
.
courseType
!==
prevProps
.
courseType
this
.
props
.
courseType
!==
prevProps
.
courseType
)
{
)
{
this
.
handleFetchScheduleList
(
this
.
props
);
this
.
handleFetchScheduleList
(
this
.
props
);
...
@@ -78,10 +78,10 @@ class VideoList extends React.Component {
...
@@ -78,10 +78,10 @@ class VideoList extends React.Component {
let
hours
=
Math
.
floor
(
time
/
3600
);
let
hours
=
Math
.
floor
(
time
/
3600
);
let
mins
=
Math
.
floor
(
diff
/
60
);
let
mins
=
Math
.
floor
(
diff
/
60
);
let
seconds
=
Math
.
floor
(
time
%
60
);
let
seconds
=
Math
.
floor
(
time
%
60
);
hours
=
hours
<
10
?
"0"
+
hours
:
hours
;
hours
=
hours
<
10
?
'0'
+
hours
:
hours
;
mins
=
mins
<
10
?
"0"
+
mins
:
mins
;
mins
=
mins
<
10
?
'0'
+
mins
:
mins
;
seconds
=
seconds
<
10
?
"0"
+
seconds
:
seconds
;
seconds
=
seconds
<
10
?
'0'
+
seconds
:
seconds
;
return
hours
+
":"
+
mins
+
":"
+
seconds
;
return
hours
+
':'
+
mins
+
':'
+
seconds
;
};
};
// 请求表头
// 请求表头
parseColumns
=
()
=>
{
parseColumns
=
()
=>
{
...
@@ -90,71 +90,58 @@ class VideoList extends React.Component {
...
@@ -90,71 +90,58 @@ class VideoList extends React.Component {
title
:
(
title
:
(
<
span
>
<
span
>
<
span
>
课程信息
</
span
>
<
span
>
课程信息
</
span
>
<
Tooltip
<
Tooltip
title=
{
<
div
>
已加入该分类的课程不支持重复选择,因此不显示。
</
div
>
}
>
title=
{
<
div
>
已加入该分类的课程不支持重复选择,因此不显示。
</
div
>
}
>
<
i
<
i
className=
"icon iconfont"
className=
'icon iconfont'
style=
{
{
style=
{
{
marginLeft
:
"5px"
,
marginLeft
:
'5px'
,
cursor
:
"pointer"
,
cursor
:
'pointer'
,
color
:
"#bfbfbf"
,
color
:
'#bfbfbf'
,
fontSize
:
"14px"
,
fontSize
:
'14px'
,
fontWeight
:
"400"
fontWeight
:
'400'
,
}
}
}
}
>
>


</
i
>
</
i
>
</
Tooltip
>
</
Tooltip
>
</
span
>
</
span
>
),
),
key
:
"scheduleName"
,
key
:
'scheduleName'
,
dataIndex
:
"scheduleName"
,
dataIndex
:
'scheduleName'
,
width
:
371
,
width
:
371
,
render
:
(
val
,
record
)
=>
{
render
:
(
val
,
record
)
=>
{
const
{
coverUrl
,
scheduleVideoUrl
}
=
record
;
const
{
coverUrl
,
scheduleVideoUrl
}
=
record
;
return
(
return
(
<
div
className=
"record__item"
>
<
div
className=
'record__item'
>
{
/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */
}
{
/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */
}
<
img
<
img
className=
'course-cover'
src=
{
coverUrl
||
`${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
className=
"course-cover"
src=
{
coverUrl
||
`${scheduleVideoUrl}?x-oss-process=video/snapshot,t_0,m_fast`
}
/>
{
record
.
courseName
.
length
>
25
?
(
{
record
.
courseName
.
length
>
25
?
(
<
Tooltip
title=
{
record
.
courseName
}
>
<
Tooltip
title=
{
record
.
courseName
}
>
<
div
className=
"course-name"
>
{
record
.
courseName
}
</
div
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
Tooltip
>
</
Tooltip
>
)
:
(
)
:
(
<
div
className=
"course-name"
>
{
record
.
courseName
}
</
div
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
)
}
)
}
</
div
>
</
div
>
);
);
},
},
},
},
{
{
title
:
"课程时长"
,
title
:
'课程时长'
,
key
:
"videoDuration"
,
key
:
'videoDuration'
,
dataIndex
:
"videoDuration"
,
dataIndex
:
'videoDuration'
,
render
:
(
text
,
item
)
=>
{
render
:
(
text
,
item
)
=>
{
return
<
span
>
{
text
?
this
.
dealTimeDuration
(
text
)
:
"-"
}
</
span
>;
return
<
span
>
{
text
?
this
.
dealTimeDuration
(
text
)
:
'-'
}
</
span
>;
},
},
},
},
{
{
title
:
"课程分类"
,
title
:
'课程分类'
,
key
:
"categoryName"
,
key
:
'categoryName'
,
dataIndex
:
"categoryName"
,
dataIndex
:
'categoryName'
,
render
:
(
val
,
record
)
=>
{
render
:
(
val
,
record
)
=>
{
return
(
return
(
<
div
className=
"record__item"
>
<
div
className=
'record__item'
>
{
record
.
categoryOneName
}
{
record
.
categoryOneName
}
{
record
.
categoryTwoName
?
`-${record.categoryTwoName}`
:
""
}
{
record
.
categoryTwoName
?
`-${record.categoryTwoName}`
:
''
}
</
div
>
</
div
>
);
);
},
},
...
@@ -167,11 +154,7 @@ class VideoList extends React.Component {
...
@@ -167,11 +154,7 @@ class VideoList extends React.Component {
let
{
selectedRowKeys
}
=
this
.
state
;
let
{
selectedRowKeys
}
=
this
.
state
;
let
_list
=
[];
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectedRowKeys
,
(
item
)
=>
item
.
id
==
record
.
id
))
{
if
(
selected
||
!
_
.
find
(
selectedRowKeys
,
(
item
)
=>
item
.
id
==
record
.
id
))
{
_list
=
_
.
uniq
(
_list
=
_
.
uniq
(
selectedRowKeys
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
selectedRowKeys
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
}
else
{
}
else
{
_list
=
_
.
reject
(
selectedRowKeys
,
(
item
)
=>
item
.
id
===
record
.
id
);
_list
=
_
.
reject
(
selectedRowKeys
,
(
item
)
=>
item
.
id
===
record
.
id
);
}
}
...
@@ -182,27 +165,21 @@ class VideoList extends React.Component {
...
@@ -182,27 +165,21 @@ class VideoList extends React.Component {
const
{
dataSource
=
[],
totalCount
,
query
,
selectedRowKeys
}
=
this
.
state
;
const
{
dataSource
=
[],
totalCount
,
query
,
selectedRowKeys
}
=
this
.
state
;
const
{
current
,
size
}
=
query
;
const
{
current
,
size
}
=
query
;
const
rowSelection
=
{
const
rowSelection
=
{
selectedRowKeys
:
_
.
pluck
(
selectedRowKeys
,
"id"
),
selectedRowKeys
:
_
.
pluck
(
selectedRowKeys
,
'id'
),
onSelect
:
this
.
selectLiveList
,
onSelect
:
this
.
selectLiveList
,
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
let
_list
=
[];
if
(
selected
)
{
if
(
selected
)
{
_list
=
_
.
uniq
(
_list
=
_
.
uniq
(
selectedRowKeys
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
selectedRowKeys
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
}
else
{
}
else
{
_list
=
_
.
reject
(
selectedRowKeys
,
(
item
)
=>
_list
=
_
.
reject
(
selectedRowKeys
,
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
));
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
)
);
}
}
this
.
setState
({
selectedRowKeys
:
_list
});
this
.
setState
({
selectedRowKeys
:
_list
});
},
},
};
};
return
(
return
(
<
div
className=
"live-list"
>
<
div
className=
'live-list'
>
<
TableSelectedData
<
TableSelectedData
selectedNum=
{
selectedRowKeys
.
length
}
selectedNum=
{
selectedRowKeys
.
length
}
clearSelectedData=
{
()
=>
{
clearSelectedData=
{
()
=>
{
...
@@ -215,14 +192,14 @@ class VideoList extends React.Component {
...
@@ -215,14 +192,14 @@ class VideoList extends React.Component {
rowKey=
{
(
record
)
=>
record
.
id
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
dataSource
}
dataSource=
{
dataSource
}
columns=
{
this
.
parseColumns
()
}
columns=
{
this
.
parseColumns
()
}
size=
"middle"
size=
'middle'
rowSelection=
{
rowSelection
}
rowSelection=
{
rowSelection
}
pagination=
{
false
}
pagination=
{
false
}
bordered
bordered
className=
"video-list-table"
className=
'video-list-table'
/>
/>
<
div
className=
"box-footer"
>
<
div
className=
'box-footer'
>
{
totalCount
>
0
&&
(
{
totalCount
>
0
&&
(
<
PageControl
<
PageControl
current=
{
current
-
1
}
current=
{
current
-
1
}
...
...
src/modules/task-center/data-center/Index.tsx
View file @
5314960e
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
"react-router-dom"
;
import
{
Tabs
}
from
'antd'
;
import
{
Tabs
}
from
'antd'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
Service
from
'@/common/js/service'
;
import
Service
from
'@/common/js/service'
;
import
Breadcrumbs
from
"@/components/Breadcrumbs"
;
import
Breadcrumbs
from
"@/components/Breadcrumbs"
;
import
UserLearningData
from
'./UserLearningData'
;
import
DataInfo
from
'./components/DataInfo'
import
DataInfo
from
'./components/DataInfo'
import
CourseTable
from
'./components/CourseTable'
;
import
CourseTable
from
'./components/CourseTable'
;
import
DataAnalysic
from
'./components/DataAnalysic'
;
import
ExamTable
from
'./components/ExamTable'
;
import
ExamTable
from
'./components/ExamTable'
;
import
StudyTable
from
'./components/StudyTable'
;
import
StudyTable
from
'./components/StudyTable'
;
import
'./index.less'
import
'./index.less'
const
{
TabPane
}
=
Tabs
;
const
{
TabPane
}
=
Tabs
;
function
DataCenter
(
props
:
any
)
{
function
DataCenter
(
props
:
any
)
{
const
{
match
:
{
params
:
{
taskId
}
}
}
=
props
;
const
{
match
}
=
props
;
const
{
params
:
{
taskId
}
}
=
match
;
const
[
info
,
setInfo
]
=
useState
<
any
>
({})
const
[
info
,
setInfo
]
=
useState
<
any
>
({})
const
[
tabKey
,
setTabKey
]
=
useState
<
any
>
(
''
)
const
[
tabKey
,
setTabKey
]
=
useState
<
any
>
(
''
)
...
@@ -44,8 +47,8 @@ function DataCenter(props: any) {
...
@@ -44,8 +47,8 @@ function DataCenter(props: any) {
res
.
result
.
trainingStageList
.
map
((
item
:
any
)
=>
{
res
.
result
.
trainingStageList
.
map
((
item
:
any
)
=>
{
item
.
open
=
true
item
.
open
=
true
})
})
res
.
result
.
cover
=
res
.
result
.
courseMediaVOS
.
filter
((
item
:
any
)
=>
item
.
contentType
===
'COVER'
)[
0
]
||
{};
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
]
||
{};
res
.
result
.
intro
=
res
.
result
.
courseMediaVOS
.
filter
((
item
:
any
)
=>
item
.
contentType
===
'INTRO'
)[
0
]
||
{};
setInfo
(
res
.
result
)
setInfo
(
res
.
result
)
})
})
}
}
...
@@ -72,7 +75,13 @@ function DataCenter(props: any) {
...
@@ -72,7 +75,13 @@ function DataCenter(props: any) {
</
Tabs
>
</
Tabs
>
</
div
>
</
div
>
<
Route
path=
{
`${match.url}/analysic/:id`
}
render=
{
()
=>
{
return
<
DataAnalysic
/>;
}
}
/>
<
Route
path=
{
`${props.match.url}/user-learning-data/:storeCustomerId`
}
render=
{
()
=>
<
UserLearningData
taskId=
{
taskId
}
/>
}
/>
</
div
>
</
div
>
}
}
...
...
src/modules/task-center/data-center/components/DataAnalysic.tsx
0 → 100644
View file @
5314960e
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/ExamData.tsx
0 → 100644
View file @
5314960e
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
View file @
5314960e
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
"react-router-dom"
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
Service
from
'@/common/js/service'
;
import
Service
from
'@/common/js/service'
;
import
User
from
'@/common/js/user'
;
import
User
from
'@/common/js/user'
;
function
ExamTable
(
props
:
any
)
{
function
ExamTable
(
props
:
any
)
{
const
{
match
}
=
props
;
console
.
log
(
match
)
const
[
query
,
setQuery
]
=
useState
<
any
>
({
const
[
query
,
setQuery
]
=
useState
<
any
>
({
current
:
1
,
size
:
10
,
current
:
1
,
size
:
10
,
taskId
:
props
.
taskId
,
taskId
:
props
.
taskId
,
...
@@ -22,8 +25,8 @@ function ExamTable(props: any) {
...
@@ -22,8 +25,8 @@ function ExamTable(props: any) {
function
getList
()
{
function
getList
()
{
Service
.
Hades
(
'public/hades/queryTrainingExamUserData'
,
query
).
then
((
res
:
any
)
=>
{
Service
.
Hades
(
'public/hades/queryTrainingExamUserData'
,
query
).
then
((
res
:
any
)
=>
{
setList
(
res
.
result
.
records
)
setList
(
res
.
result
.
records
)
;
setTotal
(
res
.
result
.
t
atal
)
setTotal
(
res
.
result
.
t
otal
);
})
})
}
}
...
@@ -79,7 +82,11 @@ function ExamTable(props: any) {
...
@@ -79,7 +82,11 @@ function ExamTable(props: any) {
render
:
(
val
:
any
,
record
:
any
)
=>
{
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
(
return
(
<
div
className=
'operate-area'
>
<
div
className=
'operate-area'
>
<
span
className=
'operate-item'
onClick=
{
()
=>
{
}
}
>
<
span
className=
'operate-item'
style=
{
{
color
:
'rgba(41, 102, 255, 1)'
,
cursor
:
'pointer'
}
}
onClick=
{
()
=>
{
props
.
history
.
push
({
pathname
:
`${match.url}/analysic/${record.examId}`
,
});
}
}
>
查看数据
查看数据
</
span
>
</
span
>
...
@@ -90,6 +97,7 @@ function ExamTable(props: any) {
...
@@ -90,6 +97,7 @@ function ExamTable(props: any) {
];
];
return
<
div
className=
"study_Table"
>
return
<
div
className=
"study_Table"
>
<
div
style=
{
{
marginTop
:
12
}
}
>
<
div
style=
{
{
marginTop
:
12
}
}
>
...
...
src/modules/task-center/data-center/components/LeftStageList.jsx
View file @
5314960e
...
@@ -31,12 +31,12 @@ function LeftStageList(props) {
...
@@ -31,12 +31,12 @@ function LeftStageList(props) {
>
>
<
div
className=
"icon"
>
<
div
className=
"icon"
>
{
item
.
isShowMoreCourse
?
(
{
item
.
isShowMoreCourse
?
(
<
span
className=
"icon iconfont edit-icon"
>
æ
b2
;
</
span
>
<
span
className=
"icon iconfont edit-icon"
>
æ
77
;
</
span
>
)
:
(
)
:
(
<
span
className=
"icon iconfont edit-icon"
>

</
span
>
<
span
className=
"icon iconfont edit-icon"
>

</
span
>
)
}
)
}
</
div
>
</
div
>
<
div
className=
"stage-name"
>
<
div
className=
"stage-name
oneLineText
"
>
{
ENUM
.
IndexToSort
[
index
+
1
]
}
、
{
item
.
stageName
}
{
ENUM
.
IndexToSort
[
index
+
1
]
}
、
{
item
.
stageName
}
</
div
>
</
div
>
</
div
>
</
div
>
...
...
src/modules/task-center/data-center/components/StudyTable.tsx
View file @
5314960e
...
@@ -8,8 +8,7 @@ import Service from '@/common/js/service';
...
@@ -8,8 +8,7 @@ import Service from '@/common/js/service';
import
ENUM
from
'../../enum'
;
import
ENUM
from
'../../enum'
;
import
User
from
'@/common/js/user'
;
import
User
from
'@/common/js/user'
;
import
moment
from
'moment'
;
import
moment
from
'moment'
;
import
UserLearningData
from
'../UserLearningData'
;
import
{
timers
}
from
'jquery'
;
const
{
Search
}
=
Input
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
const
{
Option
}
=
Select
;
declare
var
formatDate
:
any
;
declare
var
formatDate
:
any
;
...
@@ -294,7 +293,7 @@ function StudyTable(props: any) {
...
@@ -294,7 +293,7 @@ function StudyTable(props: any) {
</
div
>
</
div
>
)
}
)
}
</
div
>
</
div
>
<
Route
path=
{
`${props.match.url}/user-learning-data/:storeCustomerId`
}
render=
{
()
=>
<
UserLearningData
taskId=
{
props
.
taskId
}
/>
}
/>
</
div
>
</
div
>
}
}
...
...
src/modules/task-center/data-center/components/UserData.tsx
0 → 100644
View file @
5314960e
This diff is collapsed.
Click to expand it.
src/modules/task-center/data-center/components/dataAnalysic.less
0 → 100644
View file @
5314960e
.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/userData.less
0 → 100644
View file @
5314960e
.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/train-task/components/RelatedExamDrawer.jsx
View file @
5314960e
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Author: yuananting
* @Date: 2021-08-03 17:05:32
* @Date: 2021-08-03 17:05:32
* @LastEditors: yuananting
* @LastEditors: yuananting
* @LastEditTime: 2021-08-1
1 11:49:11
* @LastEditTime: 2021-08-1
6 16:36:59
* @Description: 新建培训任务-关联考试抽屉
* @Description: 新建培训任务-关联考试抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
...
@@ -65,7 +65,7 @@ function RelatedExamDrawer(props) {
...
@@ -65,7 +65,7 @@ function RelatedExamDrawer(props) {
paperId
,
paperId
,
examName
,
examName
,
passRate
,
passRate
,
examDuration
,
examDuration
:
(
examDuration
||
0
)
*
60
*
1000
,
examDesc
,
examDesc
,
needOptionDisorder
,
needOptionDisorder
,
resultShow
,
resultShow
,
...
...
src/modules/task-center/train-task/modal/ChooseAssignorModal.jsx
View file @
5314960e
...
@@ -2,13 +2,13 @@
...
@@ -2,13 +2,13 @@
* @Author: yuananting
* @Author: yuananting
* @Date: 2021-08-05 17:09:36
* @Date: 2021-08-05 17:09:36
* @LastEditors: yuananting
* @LastEditors: yuananting
* @LastEditTime: 2021-08-1
3 19:18:54
* @LastEditTime: 2021-08-1
6 14:47:51
* @Description: 新建培训任务-选择指派对象
* @Description: 新建培训任务-选择指派对象
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
React
,
{
useState
,
useEffect
,
useRef
}
from
'react'
;
import
{
Modal
,
Tree
,
Tooltip
,
AutoComplete
,
Tabs
}
from
'antd'
;
import
{
Modal
,
Tree
,
Tooltip
,
AutoComplete
,
Tabs
,
Input
,
Checkbox
}
from
'antd'
;
import
User
from
'@/common/js/user'
;
import
User
from
'@/common/js/user'
;
import
{
DepType
}
from
'@/domains/store-domain/constants'
;
import
{
DepType
}
from
'@/domains/store-domain/constants'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
import
StoreService
from
'@/domains/store-domain/storeService'
;
...
@@ -17,22 +17,38 @@ import './ChooseAssignorModal.less';
...
@@ -17,22 +17,38 @@ import './ChooseAssignorModal.less';
const
{
TabPane
}
=
Tabs
;
const
{
TabPane
}
=
Tabs
;
const
{
DirectoryTree
}
=
Tree
;
const
{
DirectoryTree
}
=
Tree
;
const
{
Search
}
=
Input
;
function
ChooseAssignorModal
(
props
)
{
function
ChooseAssignorModal
(
props
)
{
const
AssignTypeEnum
=
{
departMentTab
:
'SECTION'
,
postGrouptab
:
'POST'
,
customGroupTab
:
'CUSTOM'
,
};
const
[
structureData
,
setStructureData
]
=
useState
([]);
const
[
structureData
,
setStructureData
]
=
useState
([]);
const
[
activeKey
,
setActiveKey
]
=
useState
(
'departMentTab'
);
const
[
activeKey
,
setActiveKey
]
=
useState
(
'departMentTab'
);
const
[
checkedAssignorList
,
setCheckedAssignorList
]
=
useState
(
props
.
currentAssignorList
||
[]);
// 勾选的指派对象
const
[
checkedAssignorList
,
setCheckedAssignorList
]
=
useState
(
props
.
currentAssignorList
||
[]);
// 勾选的指派对象
const
[
checkedAssignorKeys
,
setCheckedAssignorKeys
]
=
useState
(
props
.
currentAssignorList
.
map
((
item
)
=>
item
.
checkedId
)
||
[]);
const
[
checkedAssignorKeys
,
setCheckedAssignorKeys
]
=
useState
(
props
.
currentAssignorList
.
map
((
item
)
=>
item
.
checkedId
)
||
[]);
const
[
completeOptions
,
setCompleteOption
]
=
useState
([]);
const
[
completeOptions
,
setCompleteOption
]
=
useState
([]);
const
[
searchKey
,
setSearchKey
]
=
useState
(
''
);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
open
,
setOpen
]
=
useState
(
false
);
const
[
queryName
,
setQueryName
]
=
useState
(
''
);
// 搜索框内的值
const
queryNameRef
=
useRef
(
null
);
const
timer
=
useRef
(
null
);
const
AssignTypeEnum
=
{
departMentTab
:
'SECTION'
,
postGrouptab
:
'POST'
,
customGroupTab
:
'CUSTOM'
,
};
useEffect
(()
=>
{
useEffect
(()
=>
{
queryNameRef
.
current
=
queryName
;
setOpen
(
!!
queryName
);
clearTimeout
(
timer
.
current
);
timer
.
current
=
setTimeout
(()
=>
{
if
(
!!
queryName
)
return
getCompleteOptionData
(
queryNameRef
.
current
);
setCompleteOption
([]);
},
500
);
},
[
queryName
]);
useEffect
(()
=>
{
setQueryName
(
''
);
// 切换tab时搜索置空
setCompleteOption
([]);
setStructureData
([]);
getStructureData
();
getStructureData
();
},
[
activeKey
]);
},
[
activeKey
]);
...
@@ -40,7 +56,7 @@ function ChooseAssignorModal(props) {
...
@@ -40,7 +56,7 @@ function ChooseAssignorModal(props) {
const
params
=
{
const
params
=
{
depType
:
DepType
[
activeKey
],
depType
:
DepType
[
activeKey
],
enterpriseId
:
User
.
getEnterpriseId
(),
enterpriseId
:
User
.
getEnterpriseId
(),
source
:
0
,
//0代表来自企培
source
:
0
,
//
0代表来自企培
storeId
:
User
.
getStoreId
(),
storeId
:
User
.
getStoreId
(),
userId
:
User
.
getUserId
(),
userId
:
User
.
getUserId
(),
whetherCount
:
false
,
whetherCount
:
false
,
...
@@ -117,14 +133,16 @@ function ChooseAssignorModal(props) {
...
@@ -117,14 +133,16 @@ function ChooseAssignorModal(props) {
}
}
function
renderTitle
(
title
)
{
function
renderTitle
(
title
)
{
return
<
span
>
{
title
}
</
span
>;
return
<
span
className=
'catalog-title'
>
{
title
}
</
span
>;
}
}
function
renderItem
(
record
,
type
)
{
function
renderItem
(
record
,
type
)
{
return
{
return
{
value
:
record
.
userName
||
record
.
name
,
value
:
record
.
userName
||
record
.
name
,
label
:
(
label
:
(
<
Checkbox
>
<
div
<
div
className=
'search-result-item'
style=
{
{
style=
{
{
display
:
'flex'
,
display
:
'flex'
,
justifyContent
:
'space-between'
,
justifyContent
:
'space-between'
,
...
@@ -132,28 +150,35 @@ function ChooseAssignorModal(props) {
...
@@ -132,28 +150,35 @@ function ChooseAssignorModal(props) {
depId=
{
record
.
id
}
depId=
{
record
.
id
}
type=
{
type
}
>
type=
{
type
}
>
{
type
===
'user'
?
(
{
type
===
'user'
?
(
<
div
>
<
div
className=
'search-result-item__left'
>
<
WWOpenDataCom
type=
'userName'
openid=
{
record
.
userName
}
/>
<
WWOpenDataCom
type=
'userName'
openid=
{
record
.
userName
}
/>
</
div
>
</
div
>
)
:
(
)
:
(
<
div
>
<
div
className=
'search-result-item__left'
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
record
.
name
}
/>
{
activeKey
===
'departMentTab'
?
<
WWOpenDataCom
type=
'departmentName'
openid=
{
record
.
name
}
/>
:
<
span
>
{
record
.
name
}
</
span
>
}
</
div
>
</
div
>
)
}
)
}
{
type
===
'user'
&&
{
type
===
'user'
&&
(
record
.
postDepNamesList
.
map
((
item
,
index
)
=>
{
<
div
className=
'search-result-item__right'
>
<
Tooltip
title=
{
<
div
>
{
handleDepName
(
record
.
depNamesList
)
}
</
div
>
}
placement=
'top'
arrowPointAtCenter
>
{
record
.
depNamesList
.
map
((
item
,
index
)
=>
{
return
(
return
(
<
span
>
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
{
index
<
record
.
depNamesList
.
length
-
1
?
';'
:
''
}
</
span
>
</
span
>
);
);
})
}
})
}
</
Tooltip
>
</
div
>
)
}
{
type
===
'post'
&&
(
{
type
===
'post'
&&
(
<
span
type=
'post'
openid=
{
record
.
parentName
}
>
<
span
type=
'post'
openid=
{
record
.
parentName
}
>
{
record
.
parentName
}
{
record
.
parentName
}
</
span
>
</
span
>
)
}
)
}
</
div
>
</
div
>
</
Checkbox
>
),
),
};
};
}
}
...
@@ -161,7 +186,7 @@ function ChooseAssignorModal(props) {
...
@@ -161,7 +186,7 @@ function ChooseAssignorModal(props) {
function
getCompleteOptionData
(
value
)
{
function
getCompleteOptionData
(
value
)
{
setCompleteOption
([]);
setCompleteOption
([]);
const
params
=
{
const
params
=
{
depType
:
DepType
[
props
.
treeType
],
depType
:
DepType
[
activeKey
],
queryName
:
value
,
queryName
:
value
,
enterpriseId
:
User
.
getEnterpriseId
(),
enterpriseId
:
User
.
getEnterpriseId
(),
source
:
0
,
//0代表来自企培
source
:
0
,
//0代表来自企培
...
@@ -185,7 +210,7 @@ function ChooseAssignorModal(props) {
...
@@ -185,7 +210,7 @@ function ChooseAssignorModal(props) {
});
});
}
}
if
(
departmentVOList
.
length
>
0
)
{
if
(
departmentVOList
.
length
>
0
)
{
switch
(
props
.
treeType
)
{
switch
(
activeKey
)
{
case
'departMentTab'
:
case
'departMentTab'
:
departmentGroupObj
.
label
=
renderTitle
(
'部门'
);
departmentGroupObj
.
label
=
renderTitle
(
'部门'
);
break
;
break
;
...
@@ -203,7 +228,7 @@ function ChooseAssignorModal(props) {
...
@@ -203,7 +228,7 @@ function ChooseAssignorModal(props) {
});
});
}
}
if
(
subLevelDepartmentVOList
.
length
>
0
)
{
if
(
subLevelDepartmentVOList
.
length
>
0
)
{
switch
(
props
.
treeType
)
{
switch
(
activeKey
)
{
case
'postGrouptab'
:
case
'postGrouptab'
:
postobj
.
label
=
renderTitle
(
'岗位'
);
postobj
.
label
=
renderTitle
(
'岗位'
);
break
;
break
;
...
@@ -220,27 +245,51 @@ function ChooseAssignorModal(props) {
...
@@ -220,27 +245,51 @@ function ChooseAssignorModal(props) {
if
(
Object
.
keys
(
userObj
).
length
!==
0
)
{
if
(
Object
.
keys
(
userObj
).
length
!==
0
)
{
_completeOptions
.
push
(
userObj
);
_completeOptions
.
push
(
userObj
);
}
}
if
(
Object
.
keys
(
departmentGroupObj
).
length
!==
0
)
{
_completeOptions
.
push
(
departmentGroupObj
);
}
if
(
Object
.
keys
(
postobj
).
length
!==
0
)
{
if
(
Object
.
keys
(
postobj
).
length
!==
0
)
{
_completeOptions
.
push
(
postobj
);
_completeOptions
.
push
(
postobj
);
}
}
if
(
Object
.
keys
(
departmentGroupObj
).
length
!==
0
)
{
_completeOptions
.
push
(
departmentGroupObj
);
}
setCompleteOption
(
_completeOptions
);
setCompleteOption
(
_completeOptions
);
});
});
}
}
// 搜索空状态渲染;
function
notFoundContentNode
()
{
return
(
<
div
className=
'empty-con'
>
<
img
src=
'https://image.xiaomaiketang.com/xm/wRDrb2pJFb.png'
className=
'empty-img'
/>
<
div
className=
'empty-text'
>
暂无数据
</
div
>
</
div
>
);
}
function
confirmSearchSelect
(
value
,
option
)
{
const
param
=
{};
setOpen
(
false
);
setQueryName
(
value
);
if
(
option
.
label
.
props
.
type
===
'user'
)
{
param
.
queryName
=
value
;
}
else
{
param
.
id
=
option
.
label
.
props
.
depId
;
}
props
.
searchUserList
(
param
,
activeKey
,
1
);
}
// 弱提示渲染
function
handlePlaceHolder
()
{
function
handlePlaceHolder
()
{
let
placeholder
=
''
;
let
placeholder
=
''
;
switch
(
props
.
treeType
)
{
switch
(
activeKey
)
{
case
'departMentTab'
:
case
'departMentTab'
:
placeholder
=
'搜索学员
姓名
、部门'
;
placeholder
=
'搜索学员、部门'
;
break
;
break
;
case
'postGrouptab'
:
case
'postGrouptab'
:
placeholder
=
'搜索学员
姓名/岗位/
岗位组'
;
placeholder
=
'搜索学员
、岗位、
岗位组'
;
break
;
break
;
case
'customGroupTab'
:
case
'customGroupTab'
:
placeholder
=
'搜索学员
姓名/自定义分组集合/自定义分组
'
;
placeholder
=
'搜索学员
、分组、分组集合
'
;
break
;
break
;
default
:
default
:
break
;
break
;
...
@@ -248,6 +297,17 @@ function ChooseAssignorModal(props) {
...
@@ -248,6 +297,17 @@ function ChooseAssignorModal(props) {
return
placeholder
;
return
placeholder
;
}
}
function
handleDepName
(
depArray
)
{
const
depArrayDom
=
depArray
.
map
((
item
,
index
)
=>
{
return
(
<
span
>
<
WWOpenDataCom
type=
'departmentName'
openid=
{
item
}
/>
;
</
span
>
);
});
return
depArrayDom
;
}
return
(
return
(
<
Modal
<
Modal
className=
'choose-assignor-modal'
className=
'choose-assignor-modal'
...
@@ -261,16 +321,13 @@ function ChooseAssignorModal(props) {
...
@@ -261,16 +321,13 @@ function ChooseAssignorModal(props) {
maskClosable=
{
false
}
>
maskClosable=
{
false
}
>
<
div
className=
'assignor-container'
>
<
div
className=
'assignor-container'
>
<
div
className=
'left-list'
>
<
div
className=
'left-list'
>
{
/*
<AutoComplete
<
AutoComplete
dropdownClassName='
certain-category
-search-dropdown'
dropdownClassName=
'
left
-search-dropdown'
dropdownMatchSelectWidth=
{
272
}
dropdownMatchSelectWidth=
{
272
}
allowClear
allowClear
onChange={(value) => setSearchKey(value)}
onChange=
{
(
value
)
=>
setQueryName
(
value
)
}
onSearch={(value) => {
notFoundContent=
{
notFoundContentNode
()
}
getCompleteOptionData(value);
value=
{
queryName
}
}}
// notFoundContent={notFoundContentNode()}
value={searchKey}
open=
{
open
}
open=
{
open
}
onFocus=
{
()
=>
{
onFocus=
{
()
=>
{
setOpen
(
true
);
setOpen
(
true
);
...
@@ -283,7 +340,9 @@ function ChooseAssignorModal(props) {
...
@@ -283,7 +340,9 @@ function ChooseAssignorModal(props) {
}
}
}
}
options=
{
completeOptions
}
options=
{
completeOptions
}
// onSelect={confirmSearchSelect}
// onSelect={confirmSearchSelect}
placeholder={handlePlaceHolder()}></AutoComplete> */
}
placeholder=
{
handlePlaceHolder
()
}
>
<
Search
style=
{
{
width
:
272
}
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
/>
</
AutoComplete
>
<
div
className=
'data-body'
>
<
div
className=
'data-body'
>
<
Tabs
size=
{
'small'
}
onChange=
{
(
key
)
=>
setActiveKey
(
key
)
}
>
<
Tabs
size=
{
'small'
}
onChange=
{
(
key
)
=>
setActiveKey
(
key
)
}
>
<
TabPane
key=
'departMentTab'
tab=
'部门'
></
TabPane
>
<
TabPane
key=
'departMentTab'
tab=
'部门'
></
TabPane
>
...
...
src/modules/task-center/train-task/modal/ChooseAssignorModal.less
View file @
5314960e
...
@@ -5,8 +5,12 @@
...
@@ -5,8 +5,12 @@
.left-list {
.left-list {
width: 50%;
width: 50%;
margin-right: 24px;
margin-right: 24px;
padding:
0
0 12px 16px;
padding:
12px
0 12px 16px;
border: 1px solid #e8e8e8;
border: 1px solid #e8e8e8;
.ant-select-auto-complete .ant-select-clear {
font-size: 14px;
right: 15px;
}
.data-body {
.data-body {
.ant-tabs-nav {
.ant-tabs-nav {
margin: 0 !important;
margin: 0 !important;
...
@@ -18,7 +22,7 @@
...
@@ -18,7 +22,7 @@
.tree-con {
.tree-con {
overflow-y: scroll;
overflow-y: scroll;
overflow-x: hidden;
overflow-x: hidden;
max-height: 3
67
px;
max-height: 3
23
px;
padding-right: 16px;
padding-right: 16px;
.ant-tree .ant-tree-treenode {
.ant-tree .ant-tree-treenode {
padding: 12px 0 !important;
padding: 12px 0 !important;
...
@@ -102,3 +106,51 @@
...
@@ -102,3 +106,51 @@
}
}
}
}
}
}
.left-search-dropdown {
.catalog-title {
font-size: 14px;
color: #666;
margin-bottom: 14px;
}
.search-result-item {
padding: 14px 0;
color: #333;
.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;
}
.ant-select-item-option-content {
padding-left: 24px;
}
.empty-con {
text-align: center;
.empty-img {
width: 150px;
height: 150px;
}
.empty-text {
color: #666;
}
}
}
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