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
e6cb1d98
Commit
e6cb1d98
authored
Aug 16, 2021
by
zhujian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix
parent
4f691a3e
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
953 additions
and
13 deletions
+953
-13
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
+1
-1
src/modules/task-center/data-center/components/StudyTable.tsx
+2
-3
src/modules/task-center/data-center/components/UserData.tsx
+428
-0
src/modules/task-center/data-center/components/dataAnalysic.less
+22
-0
src/modules/task-center/data-center/components/userData.less
+90
-0
No files found.
src/modules/task-center/data-center/Index.tsx
View file @
e6cb1d98
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
withRouter
}
from
"react-router-dom"
;
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
:
{
params
:
{
taskId
}
}
}
=
props
;
const
{
match
}
=
props
;
const
{
params
:
{
taskId
}
}
=
match
;
const
[
info
,
setInfo
]
=
useState
<
any
>
({})
const
[
tabKey
,
setTabKey
]
=
useState
<
any
>
(
''
)
...
...
@@ -44,8 +47,8 @@ function DataCenter(props: 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
]
||
{};
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
)
})
}
...
...
@@ -72,7 +75,13 @@ function DataCenter(props: any) {
</
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
>
}
...
...
src/modules/task-center/data-center/components/DataAnalysic.tsx
0 → 100644
View file @
e6cb1d98
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 @
e6cb1d98
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 @
e6cb1d98
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
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
,
...
...
@@ -22,8 +25,8 @@ function ExamTable(props: any) {
function
getList
()
{
Service
.
Hades
(
'public/hades/queryTrainingExamUserData'
,
query
).
then
((
res
:
any
)
=>
{
setList
(
res
.
result
.
records
)
setTotal
(
res
.
result
.
t
atal
)
setList
(
res
.
result
.
records
)
;
setTotal
(
res
.
result
.
t
otal
);
})
}
...
...
@@ -79,7 +82,11 @@ function ExamTable(props: any) {
render
:
(
val
:
any
,
record
:
any
)
=>
{
return
(
<
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
>
...
...
@@ -90,6 +97,7 @@ function ExamTable(props: any) {
];
return
<
div
className=
"study_Table"
>
<
div
style=
{
{
marginTop
:
12
}
}
>
...
...
src/modules/task-center/data-center/components/LeftStageList.jsx
View file @
e6cb1d98
...
...
@@ -36,7 +36,7 @@ function LeftStageList(props) {
<
span
className=
"icon iconfont edit-icon"
>

</
span
>
)
}
</
div
>
<
div
className=
"stage-name"
>
<
div
className=
"stage-name
oneLineText
"
>
{
ENUM
.
IndexToSort
[
index
+
1
]
}
、
{
item
.
stageName
}
</
div
>
</
div
>
...
...
src/modules/task-center/data-center/components/StudyTable.tsx
View file @
e6cb1d98
...
...
@@ -8,8 +8,7 @@ import Service from '@/common/js/service';
import
ENUM
from
'../../enum'
;
import
User
from
'@/common/js/user'
;
import
moment
from
'moment'
;
import
UserLearningData
from
'../UserLearningData'
;
import
{
timers
}
from
'jquery'
;
const
{
Search
}
=
Input
;
const
{
Option
}
=
Select
;
declare
var
formatDate
:
any
;
...
...
@@ -294,7 +293,7 @@ function StudyTable(props: any) {
</
div
>
)
}
</
div
>
<
Route
path=
{
`${props.match.url}/user-learning-data/:storeCustomerId`
}
render=
{
()
=>
<
UserLearningData
taskId=
{
props
.
taskId
}
/>
}
/>
</
div
>
}
...
...
src/modules/task-center/data-center/components/UserData.tsx
0 → 100644
View file @
e6cb1d98
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/dataAnalysic.less
0 → 100644
View file @
e6cb1d98
.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 @
e6cb1d98
.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;
}
}
}
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