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
6871c062
Commit
6871c062
authored
Aug 03, 2021
by
yuananting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:新增培训任务模块开发
parent
a7e01f18
Hide whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1234 additions
and
359 deletions
+1234
-359
src/common/constants/academic/taskEnum.js
+18
-0
src/common/less/icon-font.less
+3
-3
src/index.html
+3
-3
src/modules/course-manage/components/GraphicsEditor.jsx
+3
-2
src/modules/task-center/train-task/AddTrainTask.jsx
+22
-10
src/modules/task-center/train-task/AddTrainTask.less
+64
-0
src/modules/task-center/train-task/components/BasicInfo.jsx
+7
-111
src/modules/task-center/train-task/components/BasicInfo.less
+25
-27
src/modules/task-center/train-task/components/ExpiredCourseList.jsx
+44
-0
src/modules/task-center/train-task/components/ExpiredCourseList.less
+64
-0
src/modules/task-center/train-task/components/RelatedCourseDrawer.jsx
+14
-4
src/modules/task-center/train-task/components/RelatedExamDrawer.jsx
+386
-0
src/modules/task-center/train-task/components/RelatedExamDrawer.less
+15
-0
src/modules/task-center/train-task/components/TrainContent.jsx
+303
-40
src/modules/task-center/train-task/components/TrainContent.less
+155
-19
src/modules/task-center/train-task/components/TrainFilter.jsx
+4
-5
src/modules/task-center/train-task/components/TrainFilter.less
+5
-21
src/modules/task-center/train-task/components/TrainList.jsx
+38
-60
src/modules/task-center/train-task/components/TrainList.less
+61
-54
No files found.
src/common/constants/academic/taskEnum.js
0 → 100644
View file @
6871c062
/*
* @Author: yuananting
* @Date: 2021-08-02 11:50:37
* @LastEditors: yuananting
* @LastEditTime: 2021-08-02 13:56:52
* @Description: 任务中心
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
const
LearningContentIcon
=
{
LIVE
:
'https://image.xiaomaiketang.com/xm/jyFhCtaKfi.png'
,
VOICE
:
'https://image.xiaomaiketang.com/xm/2T2k5Tbmpy.png'
,
PICTURE
:
'https://image.xiaomaiketang.com/xm/yzjNwGX6TY.png'
,
EAXM
:
'https://image.xiaomaiketang.com/xm/fCDPp2Eenc.png'
,
HOMEWORK
:
'https://image.xiaomaiketang.com/xm/hShsAzzppZ.png'
,
};
export
{
LearningContentIcon
};
src/common/less/icon-font.less
View file @
6871c062
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.woff2?t=162781078685
8') format('woff2'),
url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.woff?t=162781078685
8') format('woff'),
url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.ttf?t=162781078685
8') format('truetype');
src: url('//at.alicdn.com/t/font_2223403_
sv3ehwf2rr.woff2?t=162790351801
8') format('woff2'),
url('//at.alicdn.com/t/font_2223403_
sv3ehwf2rr.woff?t=162790351801
8') format('woff'),
url('//at.alicdn.com/t/font_2223403_
sv3ehwf2rr.ttf?t=162790351801
8') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
...
...
src/index.html
View file @
6871c062
<!--
* @Author: 吴文洁
* @Date: 2020-08-24 12:20:57
* @LastEditors:
Please set LastEditors
* @LastEditTime: 2021-0
7-08 19:38:5
2
* @LastEditors:
yuananting
* @LastEditTime: 2021-0
8-03 14:08:1
2
* @Description:
* @Copyright: 杭州杰竞科技有限公司 版权所有
-->
...
...
@@ -29,7 +29,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_
e1xgcyaur7
.css"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_
sv3ehwf2rr
.css"
/>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
...
...
src/modules/course-manage/components/GraphicsEditor.jsx
View file @
6871c062
...
...
@@ -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/task-center/train-task/AddTrainTask.jsx
View file @
6871c062
...
...
@@ -2,13 +2,13 @@
* @Author: yuananting
* @Date: 2021-07-29 13:57:03
* @LastEditors: yuananting
* @LastEditTime: 2021-08-02 1
0:42:28
* @LastEditTime: 2021-08-02 1
7:25:17
* @Description: 任务中心-培训任务-新建页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Tabs
,
message
,
Modal
}
from
'antd'
;
import
{
Button
,
Tabs
,
message
,
Modal
,
Space
}
from
'antd'
;
import
ShowTips
from
'@/components/ShowTips'
;
import
Breadcrumbs
from
'@/components/Breadcrumbs'
;
import
BasicInfo
from
'./components/BasicInfo'
;
...
...
@@ -78,6 +78,7 @@ function AddTrainTask() {
</
Choose
>
);
}
function
handleGoBack
()
{
window
.
RCHistory
.
goBack
();
}
...
...
@@ -100,14 +101,25 @@ function AddTrainTask() {
<
div
className=
'show-tips'
>
<
ShowTips
message=
'请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利'
/>
</
div
>
<
Tabs
centered=
{
true
}
onChange=
{
(
key
)
=>
setActiveStep
(
key
)
}
>
<
TabPane
tab=
'1 基本信息'
key=
'BASIC_INFO'
>
<
BasicInfo
data=
{
basicInfo
}
onChange=
{
handleChangeBasicInfo
}
/>
</
TabPane
>
<
TabPane
tab=
'2 培训内容'
key=
'TRAIN_CONTENT'
>
<
TrainContent
data=
{
taskList
}
onChange=
{
handleChangeTaskInfo
}
/>
</
TabPane
>
</
Tabs
>
<
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
data=
{
basicInfo
}
onChange=
{
handleChangeBasicInfo
}
/>
}
{
activeStep
===
'TRAIN_CONTENT'
&&
<
TrainContent
data=
{
taskList
}
onChange=
{
handleChangeTaskInfo
}
/>
}
</
div
>
{
renderFooter
()
}
</
div
>
...
...
src/modules/task-center/train-task/AddTrainTask.less
View file @
6871c062
.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;
...
...
src/modules/task-center/train-task/components/BasicInfo.jsx
View file @
6871c062
...
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-29 14:32:24
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-30 16:23:1
1
* @LastEditTime: 2021-0
8-02 17:50:5
1
* @Description: 任务中心-培训任务-新建-基本信息
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
...
...
@@ -41,80 +41,7 @@ function BasicInfo(props) {
percentCompletePicture
,
}
=
data
;
const
isDefaultCover
=
true
;
const
helpStoreUsers
=
[
{
id
:
1
,
name
:
'y阿萨德at'
,
},
{
id
:
2
,
name
:
'ASFSDFAtgdf'
,
},
{
id
:
3
,
name
:
'sfasfasdffff'
,
},
{
id
:
4
,
name
:
'fsaf'
,
},
{
id
:
5
,
name
:
'示范法as'
,
},
{
id
:
6
,
name
:
'会尽快个何况'
,
},
{
id
:
7
,
name
:
'千多'
,
},
{
id
:
8
,
name
:
'我二合一'
,
},
{
id
:
9
,
name
:
'发顺丰'
,
},
{
id
:
10
,
name
:
'时高时低'
,
},
{
id
:
11
,
name
:
'ASFSDFAtgdf'
,
},
{
id
:
12
,
name
:
'撒的A'
,
},
{
id
:
13
,
name
:
'山东高速广东省广东省怪怪的'
,
},
{
id
:
14
,
name
:
'而言二'
,
},
{
id
:
15
,
name
:
'而已'
,
},
{
id
:
16
,
name
:
'一条鱼'
,
},
{
id
:
17
,
name
:
'水电费干啥'
,
},
{
id
:
18
,
name
:
'AddTrainTask'
,
},
];
const
helpStoreUsers
=
[];
const
assignList1
=
[
{
...
...
@@ -171,38 +98,6 @@ function BasicInfo(props) {
id
:
10
,
name
:
'iuyti第三方感受到'
,
},
{
id
:
11
,
name
:
'ASFSDFAtgdf'
,
},
{
id
:
12
,
name
:
'撒的A'
,
},
{
id
:
13
,
name
:
'耳热耳热让他一人'
,
},
{
id
:
14
,
name
:
'而言二'
,
},
{
id
:
15
,
name
:
'而已'
,
},
{
id
:
16
,
name
:
'一条鱼'
,
},
{
id
:
17
,
name
:
'水电费干啥'
,
},
{
id
:
18
,
name
:
'AddTrainTask'
,
},
];
// 使用默认封面图
...
...
@@ -312,9 +207,9 @@ function BasicInfo(props) {
</
div
>
</
FormItem
>
<
FormItem
label=
'指派学员'
required
>
<
div
className=
'item-btn'
>
添加指派对象
</
div
>
<
Button
style=
{
{
display
:
'block'
}
}
>
添加指派对象
</
Button
>
{
assignList1
.
length
+
assignList2
.
length
>
0
&&
(
<
Space
size=
{
'12'
}
direction=
{
'vertical'
}
className=
'
item
-obj'
>
<
Space
size=
{
'12'
}
direction=
{
'vertical'
}
className=
'
select
-obj'
>
{
assignList1
.
length
>
0
&&
(
<
div
className=
'obj-type-container'
>
<
div
className=
'type-title'
>
已选组织:
</
div
>
...
...
@@ -339,9 +234,9 @@ function BasicInfo(props) {
)
}
</
FormItem
>
<
FormItem
label=
'协同人员'
>
<
div
className=
'item-btn'
>
添加协同者
</
div
>
<
Button
style=
{
{
display
:
'block'
}
}
>
添加协同者
</
Button
>
{
helpStoreUsers
.
length
>
0
&&
(
<
div
className=
'
item
-obj'
>
<
div
className=
'
select
-obj'
>
{
_
.
map
(
helpStoreUsers
,
(
item
)
=>
{
return
<
Tag
closable
>
{
item
.
name
}
</
Tag
>;
})
}
...
...
@@ -353,6 +248,7 @@ function BasicInfo(props) {
maxLimit=
{
1000
}
id=
'intro'
isIntro=
{
true
}
placeholder=
'请输入培训目的'
detail=
{
{
content
:
instro
,
}
}
...
...
src/modules/task-center/train-task/components/BasicInfo.less
View file @
6871c062
...
...
@@ -46,6 +46,7 @@
}
}
}
.duration {
&__wrap {
.tips {
...
...
@@ -59,13 +60,32 @@
}
}
}
.ant-form-item-extra {
.learning-model-tips {
margin-top: 8px;
color: #999999;
line-height: 20px;
.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;
}
}
}
.learning-model-tips {
margin-top: 8px;
color: #999999;
line-height: 20px;
}
.ant-form-item {
margin-bottom: 24px !important;
.ant-form-item-label > label {
...
...
@@ -85,26 +105,4 @@
font-size: 14px;
}
}
.item-btn {
color: #2966ff;
}
.item-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;
}
}
}
}
src/modules/task-center/train-task/components/ExpiredCourseList.jsx
0 → 100644
View file @
6871c062
/*
* @Author: yuananting
* @Date: 2021-08-03 10:47:59
* @LastEditors: yuananting
* @LastEditTime: 2021-08-03 14:08:56
* @Description: 编辑培训任务-失效课程
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
from
'react'
;
import
{
List
}
from
'antd'
;
import
'./ExpiredCourseList.less'
;
import
{
LearningContentIcon
}
from
'@/common/constants/academic/taskEnum'
;
function
ExpiredCourseList
(
props
)
{
const
expiredCourseList
=
[
1
,
2
,
3
,
4
];
return
(
<
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'
>
阶段一、
</
span
>
<
span
className=
'content-name'
>
<
img
src=
{
LearningContentIcon
[
'LIVE'
]
}
/>
<
span
>
2.1 入门培训任务
</
span
>
</
span
>
<
span
className=
'teacher-name'
>
张老师
</
span
>
<
span
className=
'split'
>
|
</
span
>
<
span
className=
'course-time'
>
2020-12-12 09:00~10:00
</
span
>
<
span
className=
'del-btn'
>
删除记录
</
span
>
</
div
>
</
List
.
Item
>
)
}
/>
</
div
>
);
}
export
default
ExpiredCourseList
;
src/modules/task-center/train-task/components/ExpiredCourseList.less
0 → 100644
View file @
6871c062
.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
View file @
6871c062
...
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-08-01 17:28:30
* @LastEditors: yuananting
* @LastEditTime: 2021-08-02 1
1:09:50
* @LastEditTime: 2021-08-02 1
4:26:43
* @Description: 新建培训任务-关联课程抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
...
...
@@ -553,7 +553,6 @@ class RelatedCourseDrawer extends Component {
pictureTotalCount
,
videoCourseDivision
,
}
=
this
.
state
;
const
{
visible
}
=
this
.
props
;
return
(
<
Drawer
...
...
@@ -562,7 +561,7 @@ class RelatedCourseDrawer extends Component {
maskClosable=
{
false
}
closable=
{
true
}
onClose=
{
this
.
props
.
onClose
}
visible=
{
visibl
e
}
visible=
{
tru
e
}
mask
className=
'related-course-drawer'
>
<
div
>
...
...
@@ -873,7 +872,18 @@ class RelatedCourseDrawer extends Component {
</
div
>
<
div
className=
'footer shrink-footer'
>
<
Button
onClick=
{
this
.
props
.
onClose
}
>
取消
</
Button
>
<
Button
type=
'primary'
>
保存
</
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
>
);
...
...
src/modules/task-center/train-task/components/RelatedExamDrawer.jsx
0 → 100644
View file @
6871c062
/*
* @Author: yuananting
* @Date: 2021-08-03 17:05:32
* @LastEditors: yuananting
* @LastEditTime: 2021-08-03 18:05:53
* @Description: 新建培训任务-关联考试抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useRef
}
from
'react'
;
import
{
Drawer
,
Form
,
Input
,
Button
,
Tooltip
,
Switch
,
Radio
,
DatePicker
,
InputNumber
}
from
'antd'
;
import
GraphicsEditor
from
'@/modules/course-manage/components/GraphicsEditor'
;
import
moment
from
'moment'
;
import
'./RelatedExamDrawer.less'
;
const
{
RangePicker
}
=
DatePicker
;
function
RelatedExamDrawer
(
props
)
{
const
paperInfoInit
=
{
passScore
:
60
};
const
[
showModal
,
setShowModal
]
=
useState
(
false
);
const
[
paperInfo
,
setPaperInfo
]
=
useState
(
paperInfoInit
);
const
[
paperId
,
setPaperId
]
=
useState
(
''
);
const
[
passRate
,
setPassRate
]
=
useState
(
60
);
//及格线
const
[
examStartTime
,
setStartTime
]
=
useState
(
''
);
const
[
examEndTime
,
setExamEndTime
]
=
useState
(
''
);
const
[
examName
,
setExamName
]
=
useState
(
''
);
const
[
needPhone
,
setNeedPhone
]
=
useState
(
'DO_NOT_NEED_PHONE_VERIFY'
);
const
[
needOptionDisorder
,
setNeedOptionDisorder
]
=
useState
(
'OPTION_SORT'
);
const
[
resultContent
,
setResultContent
]
=
useState
(
'PASS_AND_SCORE'
);
const
[
answerAnalysis
,
setAnswerAnalysis
]
=
useState
(
'RIGHT_OR_WRONG'
);
const
[
resultShow
,
setResultShow
]
=
useState
(
'IMMEDIATELY'
);
const
[
examDesc
,
setExamDesc
]
=
useState
(
''
);
const
[
passScore
,
setPassScore
]
=
useState
(
100
);
const
[
desclen
,
setDescLen
]
=
useState
(
0
);
const
[
check
,
setCheck
]
=
useState
(
false
);
const
[
getData
,
setGetData
]
=
useState
(
false
);
const
[
preview
,
setPreview
]
=
useState
(
false
);
const
[
examTotal
,
setExamTotal
]
=
useState
(
0
);
const
[
examList
,
setExamList
]
=
useState
([]);
const
request
=
useRef
(
false
);
const
{
match
}
=
props
;
const
[
examDuration
,
setExamDuration
]
=
useState
(
undefined
);
function
disabledDate
(
current
)
{
// Can not select days before today and today
return
current
&&
current
<
moment
().
startOf
(
'day'
);
}
function
queryExamList
()
{
let
param
=
{
current
:
1
,
size
:
9999
,
order
:
'EXAM_START_TIME_DESC'
,
userId
:
User
.
getStoreUserId
(),
tenantId
:
User
.
getStoreId
(),
source
:
0
,
};
Service
.
Hades
(
'public/hades/queryExamPageList'
,
param
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
setExamList
(
result
.
records
||
[]);
});
}
function
queryExamDetail
()
{
Service
.
Hades
(
'public/hades/queryExamDetail'
,
{
examId
:
match
.
params
.
id
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
}).
then
((
res
)
=>
{
const
{
result
}
=
res
;
setPaperInfo
(
result
.
examPaper
);
setPaperId
(
result
.
examPaper
.
paperId
);
setStartTime
(
props
.
type
===
'edit'
?
result
.
examStartTime
:
''
);
setExamEndTime
(
props
.
type
===
'edit'
?
result
.
examEndTime
:
''
);
setExamName
(
props
.
type
===
'edit'
?
result
.
examName
:
`
${
result
.
examName
}
(复制)`
);
setPassRate
(
result
.
passRate
*
100
);
setNeedPhone
(
result
.
needPhone
);
setExamDesc
(
result
.
examDesc
);
setExamDuration
(
result
.
examDuration
/
60
/
1000
);
setAnswerAnalysis
(
result
.
answerAnalysis
);
setNeedOptionDisorder
(
result
.
needOptionDisorder
);
setPassScore
(
result
.
passScore
);
setResultContent
(
result
.
resultContent
);
setResultShow
(
result
.
resultShow
);
setGetData
(
true
);
});
}
function
handleSave
()
{
if
(
request
.
current
)
{
return
;
}
setCheck
(
true
);
const
param
=
{
paperId
,
startTime
:
examStartTime
,
endTime
:
examEndTime
,
examName
,
passRate
:
passRate
/
100
,
examStartTime
,
examEndTime
,
examDesc
,
needPhone
,
needOptionDisorder
,
resultContent
,
answerAnalysis
,
resultShow
,
examDuration
:
(
examDuration
||
0
)
*
60
*
1000
,
passScore
,
tenantId
:
User
.
getStoreId
(),
userId
:
User
.
getStoreUserId
(),
source
:
0
,
examId
:
''
,
};
if
(
!
param
.
examName
)
{
message
.
warning
(
'请输入考试名称'
);
return
;
}
if
(
param
.
examName
&&
param
.
examName
.
length
>
40
)
{
message
.
warning
(
'考试名称最多40字'
);
return
;
}
if
(
checkExist
(
param
.
examName
))
{
message
.
warning
(
'此考试名称已存在'
);
return
;
}
if
(
!
paperId
)
{
message
.
warning
(
'请选择试卷'
);
return
;
}
if
(
!
passRate
)
{
message
.
warning
(
'请输入及格线'
);
return
;
}
if
(
!
examStartTime
||
!
examEndTime
)
{
message
.
warning
(
'请选择考试起止时间'
);
return
;
}
if
(
Number
(
examStartTime
)
<
moment
().
valueOf
())
{
message
.
warning
(
'开始时间不能早于现在'
);
return
;
}
if
(
!
examDuration
)
{
message
.
warning
(
'请输入考试时长'
);
return
;
}
if
(
examStartTime
+
examDuration
*
60
*
1000
>
examEndTime
)
{
message
.
warning
(
'考试时长不得超过考试有效期时长'
);
return
;
}
if
(
desclen
>
1000
)
{
message
.
warning
(
'内容过长,不能超过1000字'
);
return
;
}
request
.
current
=
true
;
setTimeout
(()
=>
{
request
.
current
=
false
;
},
2000
);
if
(
props
.
type
===
'edit'
)
{
param
.
examId
=
match
.
params
.
id
;
}
Service
.
Hades
(
props
.
type
===
'edit'
?
'public/hades/editExam'
:
'public/hades/createExam'
,
param
).
then
((
res
)
=>
{
message
.
success
(
props
.
type
===
'edit'
?
'编辑成功'
:
'创建成功'
);
switch
(
props
.
type
)
{
case
'organizeExam'
:
// 试卷列表-组织考试进入
case
'newPaperToAddExam'
:
// 组卷保存组织考试
case
'editPaperToAddExam'
:
window
.
RCHistory
.
push
(
'/examination-manage-index'
);
break
;
case
'add'
:
case
'edit'
:
// 考试列表-新建或编辑
case
'copy'
:
// 考试列表-新建或编辑
props
.
freshList
();
props
.
history
.
goBack
();
break
;
}
});
}
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
handleGoBack
()
{
Modal
.
confirm
({
title
:
'确定要返回吗?'
,
content
:
'返回后,本次编辑的内容将不被保存'
,
okText
:
'确认返回'
,
cancelText
:
'留在本页'
,
icon
:
<
span
className=
'icon iconfont default-confirm-icon'
>

</
span
>,
onOk
:
()
=>
{
window
.
RCHistory
.
push
(
'/examination-manage-index'
);
},
});
}
// 校验考试名称是否存在
function
checkExist
(
examName
)
{
var
result
=
null
;
examList
.
length
>
0
&&
examList
.
forEach
((
item
)
=>
{
if
(
result
!=
null
)
{
return
result
;
}
if
(
props
.
type
===
'edit'
)
{
if
(
item
.
examName
===
examName
&&
item
.
examId
!==
match
.
params
.
id
)
{
result
=
item
;
}
}
else
{
if
(
item
.
examName
===
examName
)
{
result
=
item
;
}
}
});
return
result
;
}
return
(
<
Drawer
title=
'添加考试'
width=
{
720
}
maskClosable=
{
false
}
closable=
{
true
}
onClose=
{
props
.
onClose
}
visible=
{
true
}
mask
className=
'related-exam-drawer'
>
<
div
>
<
div
className=
'module-title'
>
基本信息
</
div
>
<
Form
labelCol=
{
{
span
:
4
}
}
wrapperCol=
{
{
span
:
20
}
}
layout=
'horizontal'
>
<
Form
.
Item
label=
'选择试卷'
validateStatus=
{
check
&&
!
paperId
?
'error'
:
''
}
help=
{
check
&&
!
paperId
&&
'请选择试卷'
}
required
>
<
Button
onClick=
{
()
=>
{
setShowModal
(
true
);
}
}
>
{
paperInfo
.
paperId
?
'重新选择'
:
'选择试卷'
}
</
Button
>
</
Form
.
Item
>
<
Form
.
Item
label=
'考试名称'
validateStatus=
{
check
&&
(
!
examName
||
examName
.
length
>
40
||
checkExist
(
examName
))
?
'error'
:
''
}
help=
{
check
&&
(
!
examName
?
'请输入考试名称'
:
examName
.
length
>
40
?
'考试名称最多40字'
:
checkExist
(
examName
)
&&
'此考试名称已存在'
)
}
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
?
'error'
:
''
}
help=
{
check
&&
!
examDuration
&&
'请输入考试时长'
}
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=
'考试说明'
validateStatus=
{
check
&&
desclen
>
1000
?
'error'
:
''
}
help=
{
check
&&
desclen
>
1000
&&
'最多只能输入1000个字'
}
>
<
GraphicsEditor
maxLimit=
{
1000
}
isIntro=
{
true
}
detail=
{
{
content
:
examDesc
,
}
}
onChange=
{
(
val
,
len
)
=>
{
setExamDesc
(
val
);
setDescLen
(
len
);
}
}
/>
</
Form
.
Item
>
<
div
className=
'module-title'
>
考试设置
</
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
)
=>
{
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
>
</
Drawer
>
);
}
export
default
RelatedExamDrawer
;
src/modules/task-center/train-task/components/RelatedExamDrawer.less
0 → 100644
View file @
6871c062
.related-exam-drawer {
.module-title {
font-size: 16px;
color: #333333;
line-height: 22px;
margin-bottom: 24px;
}
.ant-form-item {
margin-bottom: 24px !important;
.graphics-editor-container {
width: 550px;
height: 130px;
}
}
}
src/modules/task-center/train-task/components/TrainContent.jsx
View file @
6871c062
...
...
@@ -2,25 +2,61 @@
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditTime: 2021-08-0
2 11:14:47
* @LastEditTime: 2021-08-0
3 17:05:23
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
Component
}
from
'react'
;
import
{
Form
,
Button
,
Input
,
Space
,
DatePicker
,
Radio
,
Tag
,
Col
,
message
,
Tooltip
,
Collapse
,
Dropdown
,
Menu
,
Drawer
}
from
'antd'
;
import
{
Form
,
Input
,
Collapse
,
Dropdown
,
Menu
}
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
{
LearningContentIcon
}
from
'@/common/constants/academic/taskEnum'
;
const
{
Panel
}
=
Collapse
;
const
SortableTaskContainer
=
sortableContainer
((
props
)
=>
<
div
{
...
props
}
></
div
>);
const
SortableTaskItem
=
sortableElement
((
props
)
=>
<
div
{
...
props
}
>
{
props
.
taskitem
}
</
div
>);
const
DragHandle
=
sortableHandle
(()
=>
<
span
className=
'drag-btn'
>
::
</
span
>);
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
=
{
1
:
'一'
,
2
:
'二'
,
3
:
'三'
,
4
:
'四'
,
5
:
'五'
,
6
:
'六'
,
7
:
'七'
,
8
:
'八'
,
9
:
'九'
,
10
:
'十'
,
};
// const id = window.getParameterByName('id');
// const type = window.getParameterByName('type');
class
TrainContent
extends
Component
{
constructor
(
props
)
{
...
...
@@ -28,23 +64,107 @@ class TrainContent extends Component {
this
.
state
=
{
dataSource
:
props
.
data
,
showCourseDrawer
:
false
,
showExamDrawer
:
false
,
selectedTaskIndex
:
0
,
expiredCourseList
:
[],
// 失效课程
showStandardDetail
:
false
,
// 是否展开高级设置
};
}
componentDidMount
()
{
// if (type === 'edit') {
// this.getPlanDetail();
// this.getPlanCustomerState();
// }
// Bus.bind('editorLimit', (editorTextLength) => {
// setEditorTextLength(editorTextLength);
// });
}
getPlanDetail
=
()
=>
{
PlanService
.
getTrainingPlanDetail
({
planId
:
id
,
}).
then
((
res
)
=>
{
const
{
planId
,
planName
,
enableState
,
operateType
,
operateIds
,
percentCompleteLive
,
percentCompleteVideo
,
percentCompletePicture
,
courseMediaVOS
,
trainingTaskList
,
}
=
res
.
result
;
let
coverId
;
let
coverUrl
;
let
instro
;
let
hasIntro
=
false
;
courseMediaVOS
.
map
((
item
)
=>
{
switch
(
item
.
contentType
)
{
case
'COVER'
:
coverId
=
item
.
mediaContent
;
coverUrl
=
item
.
mediaUrl
;
break
;
case
'INTRO'
:
hasIntro
=
true
;
instro
=
item
.
mediaContent
;
break
;
default
:
break
;
}
return
item
;
});
let
_selectOperatorList
=
[];
if
(
operateIds
)
{
_selectOperatorList
=
operateIds
.
map
((
item
,
index
)
=>
{
let
_item
=
{};
_item
.
id
=
item
;
return
_item
;
});
}
setTaskList
(
trainingTaskList
);
setBasicData
({
planId
,
planName
,
coverUrl
:
coverUrl
||
defaultCover
,
coverId
,
enableState
,
selectOperatorList
:
_selectOperatorList
,
instro
,
operateType
,
percentCompleteLive
,
percentCompleteVideo
,
percentCompletePicture
,
});
setHasGetDetail
(
true
);
});
};
getPlanCustomerState
=
()
=>
{
PlanService
.
getTrainingCourseAutoCancel
({
planId
:
id
,
}).
then
((
res
)
=>
{
const
expiredCourseList
=
res
.
result
;
this
.
setState
({
expiredCourseList
});
});
};
setTrianTypeOption
=
()
=>
{
return
(
<
Menu
>
<
Menu
.
Item
key=
'course'
onClick=
{
()
=>
this
.
setState
({
showCourseDrawer
:
true
})
}
>
<
img
className=
'type-option-icon'
src=
'https://image.xiaomaiketang.com/xm/6C2GjSpnDp.png'
/>
<
span
>
课程
</
span
>
<
span
className=
'type-option-text'
>
课程
</
span
>
</
Menu
.
Item
>
<
Menu
.
Item
key=
'exam'
>
<
Menu
.
Item
key=
'exam'
onClick=
{
()
=>
this
.
setState
({
showExamDrawer
:
true
})
}
>
<
img
className=
'type-option-icon'
src=
'https://image.xiaomaiketang.com/xm/M4BEXnRWbb.png'
/>
<
span
>
考试
</
span
>
<
span
className=
'type-option-text'
>
考试
</
span
>
</
Menu
.
Item
>
<
Menu
.
Item
key=
'homework'
>
<
img
className=
'type-option-icon'
src=
'https://image.xiaomaiketang.com/xm/ypWQcFWnxB.png'
/>
<
span
>
实操作业
</
span
>
<
span
className=
'type-option-text'
>
实操作业
</
span
>
</
Menu
.
Item
>
</
Menu
>
);
...
...
@@ -66,6 +186,23 @@ class TrainContent extends Component {
}
};
onContentSortEnd
=
({
oldIndex
,
newIndex
},
parentIndex
)
=>
{
const
{
dataSource
}
=
this
.
state
;
const
_dataSource
=
[...
dataSource
];
if
(
oldIndex
!==
newIndex
)
{
_dataSource
[
parentIndex
].
courseList
=
arrayMove
([].
concat
(
dataSource
[
parentIndex
].
courseList
),
oldIndex
,
newIndex
).
filter
((
el
)
=>
!!
el
);
this
.
setState
(
{
dataSource
:
_dataSource
,
},
()
=>
{
this
.
props
.
onChange
(
_dataSource
);
}
);
}
};
handleRenameTaskName
=
(
e
,
item
)
=>
{
const
{
value
}
=
e
.
target
;
const
{
dataSource
}
=
this
.
state
;
...
...
@@ -104,25 +241,25 @@ class TrainContent extends Component {
return
Promise
.
resolve
();
};
render
Task
Info
=
(
item
,
index
)
=>
{
render
Stage
Info
=
(
item
,
index
)
=>
{
return
(
<
div
className=
'sort-
task
-item'
>
<
Choose
>
<
When
condition=
{
item
.
type
===
'input'
}
>
<
div
className=
'task-name-con'
>
{
/* <span className='number'>{index + 1}.</span> */
}
<
div
className=
'sort-
stage
-item'
>
<
div
className=
'item-info'
>
<
span
className=
'info-number'
>
{
SortConvert
[
index
+
1
]
}
、
</
span
>
<
Choose
>
<
When
condition=
{
item
.
type
===
'input'
}
>
<
Form
>
<
Form
.
Item
initialValue=
{
item
.
taskName
}
validateTrigger=
{
[
'onChange'
,
'onBlur'
]
}
name=
{
[
'
task
Name'
]
}
name=
{
[
'
stage
Name'
]
}
rules=
{
[
{
validator
:
(
rule
,
value
)
=>
this
.
handleValidatorTaskName
(
rule
,
value
),
},
]
}
>
<
Input
className=
'
task-name
-input'
className=
'
info
-input'
style=
{
{
width
:
300
}
}
placeholder=
'请输入阶段名称'
maxLength=
{
20
}
...
...
@@ -137,15 +274,12 @@ class TrainContent extends Component {
/>
</
Form
.
Item
>
</
Form
>
</
div
>
</
When
>
<
Otherwise
>
<
div
className=
'task-name-con'
>
{
/* <span className='number'>{index + 1}.</span> */
}
<
span
className=
'task-name'
>
{
item
.
taskName
}
</
span
>
</
div
>
</
Otherwise
>
</
Choose
>
</
When
>
<
Otherwise
>
<
span
className=
'info-text'
>
{
item
.
taskName
}
</
span
>
</
Otherwise
>
</
Choose
>
</
div
>
<
span
className=
'item-operate'
>
<
span
className=
'operate__item'
...
...
@@ -174,24 +308,58 @@ class TrainContent extends Component {
);
};
render
Task
Item
=
(
item
,
index
)
=>
{
render
Stage
Item
=
(
item
,
index
)
=>
{
return
(
<
Collapse
ghost
>
<
Panel
header=
{
this
.
renderTaskInfo
(
item
,
index
)
}
key=
{
index
}
>
{
/* {renderTaskItem(props.iteminfo, props.index)} */
}
<
Panel
header=
{
this
.
renderStageInfo
(
item
,
index
)
}
key=
{
index
}
>
<
SortableContentContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
(
item
)
=>
this
.
onContentSortEnd
(
item
,
index
)
}
>
{
item
.
courseList
.
map
((
contentItem
,
contentIndex
)
=>
(
<
SortableContentItem
contentitem=
{
this
.
renderContentItem
(
contentItem
,
contentIndex
,
index
)
}
index=
{
contentIndex
}
key=
{
contentIndex
}
></
SortableContentItem
>
))
}
</
SortableContentContainer
>
<
Dropdown
overlay=
{
this
.
setTrianTypeOption
()
}
className=
'add-course-btn'
onClick=
{
()
=>
{
// this.showRelatedCourseModal(index);
}
}
>
<
span
>
+ 关联课程
</
span
>
<
span
className=
'add-content-btn'
>
+ 添加学习内容
</
span
>
</
Dropdown
>
</
Panel
>
</
Collapse
>
);
};
renderContentItem
=
(
record
,
index
,
parentIndex
)
=>
{
const
{
courseState
,
courseName
,
courseType
,
courseChapterNum
}
=
record
;
return
(
<
div
className=
'sort-content-item'
>
<
div
className=
'content-info'
>
<
img
className=
'type-option-icon'
src=
{
LearningContentIcon
[
courseType
]
}
/>
<
span
className=
'content-name'
>
{
parentIndex
+
1
}
.
{
index
+
1
}
{
courseName
}
</
span
>
{
courseState
===
'EXPIRED'
&&
<
span
className=
'icon iconfont tip'
>

</
span
>
}
{
courseType
===
'LIVE'
&&
<
span
className=
'extra-info'
>
{
courseStateShow
[
record
.
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
{
dataSource
}
=
this
.
state
;
...
...
@@ -219,19 +387,114 @@ class TrainContent extends Component {
});
};
onCloseExamDrawer
=
()
=>
{
this
.
setState
({
showExamDrawer
:
false
,
});
};
confirmSelectCourse
=
(
selectList
)
=>
{
const
{
selectedTaskIndex
}
=
this
.
state
;
const
{
dataSource
}
=
this
.
state
;
const
newData
=
[...
dataSource
];
const
selectData
=
[...
newData
[
selectedTaskIndex
].
courseList
];
const
_selectData
=
[...
selectData
,
...
selectList
];
newData
[
selectedTaskIndex
].
courseList
=
_selectData
;
this
.
setState
(
{
showCourseDrawer
:
false
,
dataSource
:
newData
,
},
()
=>
{
this
.
props
.
onChange
(
newData
);
}
);
};
render
()
{
const
{
dataSource
,
showCourseDrawer
}
=
this
.
state
;
const
{
dataSource
,
showCourseDrawer
,
showExamDrawer
,
expiredCourseList
,
showStandardDetail
}
=
this
.
state
;
return
(
<
div
className=
'train-content__warp'
>
<
SortableTaskContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
this
.
onTaskSortEnd
}
>
{
dataSource
.
map
((
item
,
index
)
=>
(
<
SortableTaskItem
taskitem=
{
this
.
renderTaskItem
(
item
,
index
)
}
index=
{
index
}
key=
{
index
}
></
SortableTaskItem
>
))
}
</
SortableTaskContainer
>
<
div
className=
'add-task-btn'
onClick=
{
()
=>
this
.
addStage
()
}
>
+ 添加阶段
<
div
className=
'train-content-page'
>
<
div
className=
'train-content__warp'
>
<
SortableTaskContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
this
.
onTaskSortEnd
}
>
{
dataSource
.
map
((
item
,
index
)
=>
(
<
SortableTaskItem
taskitem=
{
this
.
renderStageItem
(
item
,
index
)
}
index=
{
index
}
key=
{
index
}
></
SortableTaskItem
>
))
}
</
SortableTaskContainer
>
<
div
className=
'add-stage-btn'
onClick=
{
()
=>
this
.
addStage
()
}
>
+ 添加阶段
</
div
>
{
showCourseDrawer
&&
<
RelatedCourseDrawer
data=
{
dataSource
}
onClose=
{
this
.
onCloseCourseDrawer
}
onSelect=
{
this
.
confirmSelectCourse
}
/>
}
{
showExamDrawer
&&
<
RelatedExamDrawer
onClose=
{
this
.
onCloseExamDrawer
}
/>
}
</
div
>
<
div
className=
'expired-info__wrap'
>
<
div
className=
'module-title'
>
失效课程
</
div
>
<
ExpiredCourseList
expiredCourseList=
{
expiredCourseList
}
/>
</
div
>
<
div
className=
'finish-standard__warp'
>
<
div
className=
'module-title'
>
高级设置
<
span
className=
{
`icon iconfont ${showStandardDetail && 'rotate-arrow'}`
}
onClick=
{
()
=>
{
this
.
setState
({
showStandardDetail
:
!
showStandardDetail
});
}
}
>

</
span
>
</
div
>
{
showStandardDetail
&&
(
<
div
className=
'detail-container'
>
<
div
className=
'title-text'
>
完成标准:
</
div
>
<
div
className=
'detail-box'
>
<
div
className=
'item-info'
>
<
img
src=
{
LearningContentIcon
[
'LIVE'
]
}
/>
<
span
>
直播课单个课程,学员学习进度达到
<
Input
// value=
{
percentCompleteLive
}
onChange=
{
(
e
)
=>
{
// this.props.onChange('percentCompleteLive', e.target.value.replace(/\D/g, ''));
}
}
// onBlur=
{(
e
)
=
>
this.percentCompleteBlur(e, 'percentCompleteLive')}
className='input-box'
/
>
%,即视为"已完成"学习
</
span
>
</
div
>
<
div
className=
'item-info'
>
<
img
src=
{
LearningContentIcon
[
'VOICE'
]
}
/>
<
span
>
线上课单个课节,学员学习进度达到
<
Input
// value=
{
percentCompleteVideo
}
onChange=
{
(
e
)
=>
{
// this.props.onChange('percentCompleteVideo', e.target.value.replace(/\D/g, ''));
}
}
// onBlur=
{(
e
)
=
>
this.percentCompleteBlur(e, 'percentCompleteVideo')}
className='input-box'
/
>
%,即课节视为"已完成"学习
</
span
>
</
div
>
<
div
className=
'item-info'
>
<
img
src=
{
LearningContentIcon
[
'PICTURE'
]
}
/>
<
span
>
图文课单个课程,学员学习进度达到
<
Input
// value=
{
percentCompletePicture
}
onChange=
{
(
e
)
=>
{
// this.props.onChange('percentCompletePicture', e.target.value.replace(/\D/g, ''));
}
}
// onBlur=
{(
e
)
=
>
this.percentCompleteBlur(e, 'percentCompletePicture')}
className='input-box'
/
>
%,即视为"已完成"学习
</
span
>
</
div
>
</
div
>
</
div
>
)
}
</
div
>
<
RelatedCourseDrawer
data=
{
dataSource
}
onClose=
{
this
.
onCloseCourseDrawer
}
visible=
{
showCourseDrawer
}
/>
</
div
>
);
}
...
...
src/modules/task-center/train-task/components/TrainContent.less
View file @
6871c062
.train-content__warp {
.ant-collapse-content {
padding-left: 24px !important;
.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;
.module-title {
height: 22px;
font-size: 16px;
color: #333333;
line-height: 22px;
.icon {
font-size: 12px;
margin-left: 8px;
color: #5e606a;
display: inline-block;
vertical-align: middle;
cursor: pointer;
}
.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;
* {
vertical-align: middle;
}
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-task-item {
.sort-stage-item {
width: calc(100% - 24px);
display: inline-flex;
align-items: center;
.ant-form-item {
margin-bottom: 0 !important;
}
.item-name {
line-height: 20px;
.item-info {
color: #333333;
}
.item-operate {
display: none;
margin-left: 30px;
...
...
@@ -28,32 +98,98 @@
}
}
}
&:hover {
.item-operate {
display: block;
}
}
.drag-btn {
margin-left: auto;
.ant-form {
display: inline-block;
.ant-form-item {
margin-bottom: 0 !important;
}
}
}
.add-course-btn {
color: #2966ff;
.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;
}
}
}
}
.add-task-btn {
.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;
background: #f7f8f9;
border-radius: 2px;
padding: 16px;
margin-top: 16px;
cursor: pointer;
display: inline-block;
}
.type-option-icon {
width: 20px;
height: 20px;
margin-right: 12px;
.ant-collapse-content {
padding-left: 24px !important;
> .ant-collapse-content-box {
padding: 0 !important;
}
}
src/modules/task-center/train-task/components/TrainFilter.jsx
View file @
6871c062
...
...
@@ -7,14 +7,12 @@
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
withRouter
}
from
'react-router-dom'
;
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
{
Option
}
=
Select
;
const
DEFAULT_QUERY
=
{
// 头部筛选默认值
...
...
@@ -29,6 +27,7 @@ const DEFAULT_CREATOR_QUERY = {
current
:
1
,
nickName
:
null
,
// 搜索值
};
function
TrainFilter
(
props
)
{
const
[
query
,
setQuery
]
=
useState
(
DEFAULT_QUERY
);
const
[
hasNext
,
setHasNext
]
=
useState
(
false
);
...
...
@@ -54,7 +53,7 @@ function TrainFilter(props) {
});
}
// 滑动加载更多
讲师列表
// 滑动加载更多
创建人列表(讲师)
function
handleScrollCreatorList
(
e
)
{
const
container
=
e
.
target
;
const
scrollToBottom
=
container
&&
container
.
scrollHeight
<=
container
.
clientHeight
+
container
.
scrollTop
;
...
...
@@ -145,7 +144,7 @@ function TrainFilter(props) {
<
div
className=
'search-condition__item'
>
<
span
className=
'search-date'
>
创建日期:
</
span
>
<
RangePicker
id=
'
course
_date_picker'
id=
'
train
_date_picker'
allowClear=
{
false
}
value=
{
query
.
startTime
?
[
moment
(
query
.
startTime
),
moment
(
query
.
endTime
)]
:
null
}
format=
{
'YYYY-MM-DD'
}
...
...
@@ -169,4 +168,4 @@ function TrainFilter(props) {
);
}
export
default
withRouter
(
TrainFilter
)
;
export
default
TrainFilter
;
src/modules/task-center/train-task/components/TrainFilter.less
View file @
6871c062
.train-filter-page {
position: relative;
margin-bottom: 4px;
.ant-input-search-button{
border-left:none;
}
.search-condition {
width: calc(100% - 80px);
display: flex;
...
...
@@ -13,26 +8,16 @@
&__item {
width: 30%;
margin-right: 3%;
margin-bottom: 12px;
line-height: 32px;
}
}
.reset-fold-area {
position: absolute;
right: 12px;
}
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
.fold-btn {
font-size: 14px;
color: #666666;
line-height: 20px;
.fold-icon {
font-size: 12px;
margin-left:4px;
.resetBtn {
color: #999999;
font-size: 18px;
margin-right: 8px;
}
}
}
\ No newline at end of file
}
src/modules/task-center/train-task/components/TrainList.jsx
View file @
6871c062
...
...
@@ -2,19 +2,17 @@
* @Author: yuananting
* @Date: 2021-07-28 14:56:52
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-30 12:01:29
* @LastEditTime: 2021-0
8-02 15:45:37
* @Description: 描述一下咯
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
useState
,
useEffect
}
from
'react'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
import
{
T
abs
,
Tooltip
,
Checkbox
,
Dropdown
,
Radio
,
Button
,
Spac
e
}
from
'antd'
;
import
{
Route
,
withRouter
}
from
'react-router-dom'
;
import
{
T
ooltip
,
Checkbox
,
Dropdown
,
Radio
,
Button
,
Space
,
Badg
e
}
from
'antd'
;
import
'./TrainList.less'
;
import
{
XMTable
,
PageControl
}
from
'@/components'
;
import
User
from
'@/common/js/user'
;
const
{
TabPane
}
=
Tabs
;
function
TrainList
(
props
)
{
const
{
query
:
{
issueState
,
myAssist
,
current
,
size
},
...
...
@@ -24,6 +22,7 @@ function TrainList(props) {
function
renderMoreOperate
(
item
)
{
return
(
<
div
className=
'live-course-more-menu'
>
<
div
className=
'operate__item'
>
取消发布
</
div
>
<
div
className=
'operate__item'
>
编辑
</
div
>
<
div
className=
'operate__item'
>
分享
</
div
>
<
div
className=
'operate__item'
>
审批作业
</
div
>
...
...
@@ -42,16 +41,16 @@ function TrainList(props) {
fixed
:
'left'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
className=
'
plan_name_item
'
>
<
img
className=
'
pla
n-cover'
src=
{
record
.
coverUrl
||
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
}
alt=
''
/>
<
div
className=
'
train-task-name
'
>
<
img
className=
'
trai
n-cover'
src=
{
record
.
coverUrl
||
'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png'
}
alt=
''
/>
<
Choose
>
<
When
condition=
{
record
.
planName
.
length
>
25
}
>
<
Tooltip
title=
{
record
.
planName
}
>
<
div
className=
'
pla
n-name'
>
{
val
}
</
div
>
<
div
className=
'
trai
n-name'
>
{
val
}
</
div
>
</
Tooltip
>
</
When
>
<
Otherwise
>
<
div
className=
'
pla
n-name'
>
{
val
}
</
div
>
<
div
className=
'
trai
n-name'
>
{
val
}
</
div
>
</
Otherwise
>
</
Choose
>
</
div
>
...
...
@@ -64,7 +63,7 @@ function TrainList(props) {
key
:
'status'
,
dataIndex
:
'status'
,
render
:
(
val
,
record
)
=>
{
return
<
div
className=
'course-number'
>
{
'未开始'
}
</
div
>;
return
<
span
>
{
'未开始'
}
</
span
>;
},
},
{
...
...
@@ -73,18 +72,17 @@ function TrainList(props) {
key
:
'courseNum'
,
dataIndex
:
'courseNum'
,
render
:
(
val
,
record
)
=>
{
return
<
div
className=
'course-number'
>
{
val
}
</
div
>;
return
<
span
>
{
val
}
</
span
>;
},
},
{
title
:
'学习人数'
,
width
:
'8%'
,
align
:
'right'
,
width
:
'10%'
,
key
:
'cultureCustomerNum'
,
dataIndex
:
'cultureCustomerNum'
,
sorter
:
true
,
render
:
(
val
)
=>
{
return
<
div
className=
'join-number'
>
{
val
}
</
div
>;
return
<
span
style=
{
{
color
:
'#2966FF'
}
}
>
{
val
}
</
span
>;
},
},
{
...
...
@@ -95,7 +93,7 @@ function TrainList(props) {
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'
5
px'
,
marginLeft
:
'
4
px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
...
...
@@ -127,14 +125,14 @@ function TrainList(props) {
title
:
'创建人'
,
key
:
'createName'
,
dataIndex
:
'createName'
,
width
:
'1
0
%'
,
width
:
'1
2
%'
,
render
:
(
val
)
=>
{
return
<
div
className=
'create-name'
>
{
val
}
</
div
>;
return
<
span
>
{
val
}
</
span
>;
},
},
{
title
:
'创建时间'
,
width
:
'1
4
%'
,
width
:
'1
2
%'
,
key
:
'created'
,
dataIndex
:
'created'
,
sorter
:
true
,
...
...
@@ -144,7 +142,7 @@ function TrainList(props) {
},
{
title
:
'更新时间'
,
width
:
'1
0
%'
,
width
:
'1
2
%'
,
key
:
'updated'
,
dataIndex
:
'updated'
,
sorter
:
true
,
...
...
@@ -165,43 +163,23 @@ function TrainList(props) {
<
div
className=
'operate__item'
onClick=
{
()
=>
toLearningDataPage
(
record
)
}
>
数据
</
div
>
{
record
.
enableState
===
'YES'
&&
(
<>
<
span
className=
'operate__item split'
>
|
</
span
>
<
div
className=
'operate__item'
onClick=
{
()
=>
{
handleShowShareModal
(
record
);
}
}
>
指派
</
div
>
</>
)
}
{
record
.
enableState
===
'YES'
&&
(
<>
<
span
className=
'operate__item split'
>
|
</
span
>
<
div
className=
'operate__item'
onClick=
{
()
=>
{
handleShowShareModal
(
record
);
}
}
>
发布
</
div
>
</>
)
}
{
(
User
.
getUserRole
()
===
'CloudManager'
||
User
.
getUserRole
()
===
'StoreManager'
)
&&
(
<>
<
span
className=
'operate__item split'
>
|
</
span
>
<
Dropdown
overlay=
{
renderMoreOperate
(
record
)
}
>
<
span
className=
'more-operate'
>
<
span
className=
'operate-text'
>
更多
</
span
>
<
span
className=
'iconfont icon'
style=
{
{
color
:
'#2966FF'
}
}
>

</
span
>
</
span
>
</
Dropdown
>
</>
)
}
<
span
className=
'split'
>
|
</
span
>
<
div
className=
'operate__item'
onClick=
{
()
=>
{
handleShowShareModal
(
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
>
);
},
...
...
@@ -240,9 +218,9 @@ function TrainList(props) {
onChange=
{
(
e
)
=>
{
handleChangeQuery
(
'issueState'
,
e
.
target
.
value
);
}
}
>
<
Radio
.
Button
value=
'ALL'
>
全部
</
Radio
.
Button
>
<
Radio
.
Button
value=
'YES'
>
已发布
</
Radio
.
Button
>
<
Radio
.
Button
value=
'NO'
>
未发布
</
Radio
.
Button
>
<
Radio
.
Button
value=
'ALL'
>
全部
(2)
</
Radio
.
Button
>
<
Radio
.
Button
value=
'YES'
>
已发布
(2)
</
Radio
.
Button
>
<
Radio
.
Button
value=
'NO'
>
未发布
(10)
</
Radio
.
Button
>
</
Radio
.
Group
>
<
Checkbox
style=
{
{
lineHeight
:
'32px'
}
}
value=
{
myAssist
}
onChange=
{
(
e
)
=>
handleChangeQuery
(
'myAssist'
,
e
.
target
.
checked
)
}
>
只看我协同的 (
{
10
}
)
...
...
@@ -260,7 +238,7 @@ function TrainList(props) {
bordered
size=
'middle'
scroll=
{
{
x
:
1600
}
}
// className='pla
n-list-table'
className=
'trai
n-list-table'
renderEmpty=
{
{
description
:
<
span
style=
{
{
display
:
'block'
,
paddingBottom
:
24
}
}
>
暂无数据
</
span
>,
}
}
...
...
src/modules/task-center/train-task/components/TrainList.less
View file @
6871c062
.train-list-page {
margin-top: 12px;
.header-line {
display: flex;
justify-content: space-between;
margin-top: 16px;
margin-bottom: 12px;
}
.ant-tabs-nav {
margin: 0 !important;
}
.course-number {
margin-right: 45px;
.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;
}
}
.plan-list-table {
.train-list-table {
.train-task-name {
display: flex;
align-items: center;
.train-cover {
width: 106px;
height: 60px;
border-radius: 2px;
margin-right: 8px;
}
.train-name {
width: 188px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height: 40px;
}
}
.operate {
display: flex;
&__item {
color: #2966ff;
cursor: pointer;
}
.split {
margin: 0 8px;
color: #bfbfbf;
}
.more-text {
color: #2966ff;
cursor: pointer;
}
}
.tip {
cursor: pointer;
color: '#bfbfbf';
margin-left: 5px;
font-weight: normal;
}
thead.ant-table-thead {
tr {
th {
padding: 10px 1
2
px;
padding: 10px 1
6
px;
}
}
}
tbody {
tr {
td.ant-table-cell {
padding:
16px 12
px;
padding:
20px 16
px;
color: #333;
}
&:nth-child(even) {
...
...
@@ -46,48 +97,4 @@
}
}
}
.plan_name_item {
display: flex;
align-items: center;
.plan-cover {
width: 106px;
height: 60px;
border-radius: 2px;
margin-right: 8px;
}
.plan-name {
width: 188px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
height: 40px;
}
}
.operate-text {
color: #2966ff;
cursor: pointer;
}
.operate {
display: flex;
&__item {
color: #2966ff;
cursor: pointer;
&.split {
margin: 0 8px;
color: #bfbfbf;
}
}
}
.join-number {
text-align: right;
margin-right: 12px;
}
.more-operate {
line-height: 20px;
}
}
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