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
bd6794c0
Commit
bd6794c0
authored
Aug 02, 2021
by
yuananting
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat:添加培训内容部分
parent
52a7b420
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1359 additions
and
52 deletions
+1359
-52
src/common/less/icon-font.less
+3
-3
src/index.html
+32
-32
src/modules/task-center/train-task/AddTrainTask.jsx
+14
-2
src/modules/task-center/train-task/components/RelatedCourseDrawer.jsx
+883
-0
src/modules/task-center/train-task/components/RelatedCourseDrawer.less
+141
-0
src/modules/task-center/train-task/components/TrainContent.jsx
+227
-15
src/modules/task-center/train-task/components/TrainContent.less
+59
-0
No files found.
src/common/less/icon-font.less
View file @
bd6794c0
@font-face {
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_
oe5p510553.woff2?t=1624259078391
') format('woff2'),
src: url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.woff2?t=1627810786858
') format('woff2'),
url('//at.alicdn.com/t/font_2223403_
oe5p510553.woff?t=1624259078391
') format('woff'),
url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.woff?t=1627810786858
') format('woff'),
url('//at.alicdn.com/t/font_2223403_
oe5p510553.ttf?t=1624259078391
') format('truetype');
url('//at.alicdn.com/t/font_2223403_
e1xgcyaur7.ttf?t=1627810786858
') format('truetype');
}
}
.iconfont {
.iconfont {
font-family: 'iconfont' !important;
font-family: 'iconfont' !important;
...
...
src/index.html
View file @
bd6794c0
...
@@ -8,30 +8,30 @@
...
@@ -8,30 +8,30 @@
-->
-->
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<html>
<head>
<head>
<meta
charset=
"utf-8"
/>
<meta
charset=
"utf-8"
/>
<link
rel=
"icon"
href=
""
/>
<link
rel=
"icon"
href=
""
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
/>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
/>
<meta
name=
"theme-color"
content=
"#000000"
/>
<meta
name=
"theme-color"
content=
"#000000"
/>
<meta
<meta
name=
"description"
name=
"description"
content=
"小麦企学院,一站式企业培训数字化服务商,通过“工具+内容”,帮助企业快速从0到1搭建数字化培训体系,并让整个培训过程可视化,降低培训成本,提升培训效率。"
content=
"小麦企学院,一站式企业培训数字化服务商,通过“工具+内容”,帮助企业快速从0到1搭建数字化培训体系,并让整个培训过程可视化,降低培训成本,提升培训效率。"
/>
/>
<meta
<meta
name=
"keywords"
name=
"keywords"
content=
"小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,素材库,培训课程,培训任务,直播课,线上课,图文课,线下活动,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂"
content=
"小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,素材库,培训课程,培训任务,直播课,线上课,图文课,线下活动,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂"
/>
/>
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link
rel=
"shortcut icon"
href=
"https://image.xiaomaiketang.com/xm/c4KiP2epBP.png"
/>
<link
rel=
"shortcut icon"
href=
"https://image.xiaomaiketang.com/xm/c4KiP2epBP.png"
/>
<!--
<!--
manifest.json provides metadata used when your web app is installed on a
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
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_oe5p510553
.css"
/>
<link
rel=
"stylesheet"
href=
"//at.alicdn.com/t/font_2223403_e1xgcyaur7
.css"
/>
<!--
<!--
Notice the use of %PUBLIC_URL% in the tags above.
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Only files inside the `public` folder can be referenced from the HTML.
...
@@ -40,19 +40,19 @@
...
@@ -40,19 +40,19 @@
work correctly both with client-side routing and a non-root public URL.
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
Learn how to configure a non-root public URL by running `npm run build`.
-->
-->
<title>
小麦企学院
</title>
<title>
小麦企学院
</title>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/iscroll-zoom-min.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/iscroll-zoom-min.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/hammer.min.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/hammer.min.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/lrz.all.bundle.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/lrz.all.bundle.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/PhotoClip.js"
></script>
<script
type=
"text/javascript"
src=
"https://image.xiaomaiketang.com/xm/PhotoClip.js"
></script>
<script
type=
"text/javascript"
charset=
"utf-8"
src=
"//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"
></script>
<script
type=
"text/javascript"
charset=
"utf-8"
src=
"//g.alicdn.com/sd/ncpc/nc.js?t=2015052012"
></script>
<script
type=
"text/javascript"
src=
"https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"
></script>
<script
type=
"text/javascript"
src=
"https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"
></script>
</head>
</head>
<body>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div
id=
"root"
></div>
<div
id=
"root"
></div>
<!--
<!--
This HTML file is a template.
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
If you open it directly in the browser, you will see an empty page.
...
@@ -62,5 +62,5 @@
...
@@ -62,5 +62,5 @@
To begin the development, run `npm start` or `yarn start`.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
-->
</body>
</body>
</html>
</html>
src/modules/task-center/train-task/AddTrainTask.jsx
View file @
bd6794c0
...
@@ -2,7 +2,7 @@
...
@@ -2,7 +2,7 @@
* @Author: yuananting
* @Author: yuananting
* @Date: 2021-07-29 13:57:03
* @Date: 2021-07-29 13:57:03
* @LastEditors: yuananting
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-30 16:35:59
* @LastEditTime: 2021-0
8-02 10:42:28
* @Description: 任务中心-培训任务-新建页面
* @Description: 任务中心-培训任务-新建页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
...
@@ -38,10 +38,18 @@ const DEFAULT_BASIC_INFO = {
...
@@ -38,10 +38,18 @@ const DEFAULT_BASIC_INFO = {
percentCompletePicture
:
100
,
percentCompletePicture
:
100
,
};
};
const
DEFAULT_TASK_LIST
=
[
{
taskName
:
'阶段一'
,
courseList
:
[],
},
];
function
AddTrainTask
()
{
function
AddTrainTask
()
{
const
type
=
getParameterByName
(
'type'
);
const
type
=
getParameterByName
(
'type'
);
const
[
activeStep
,
setActiveStep
]
=
useState
(
'BASIC_INFO'
);
const
[
activeStep
,
setActiveStep
]
=
useState
(
'BASIC_INFO'
);
const
[
basicInfo
,
setBasicInfo
]
=
useState
(
DEFAULT_BASIC_INFO
);
const
[
basicInfo
,
setBasicInfo
]
=
useState
(
DEFAULT_BASIC_INFO
);
const
[
taskList
,
setTaskList
]
=
useState
(
DEFAULT_TASK_LIST
);
function
renderFooter
()
{
function
renderFooter
()
{
return
(
return
(
...
@@ -81,6 +89,10 @@ function AddTrainTask() {
...
@@ -81,6 +89,10 @@ function AddTrainTask() {
});
});
}
}
function
handleChangeTaskInfo
(
value
)
{
setTaskList
(
value
);
}
return
(
return
(
<
div
className=
'page add-train-task'
>
<
div
className=
'page add-train-task'
>
<
Breadcrumbs
navList=
{
type
==
'add'
?
'新建培训任务'
:
'编辑培训任务'
}
goBack=
{
handleGoBack
}
/>
<
Breadcrumbs
navList=
{
type
==
'add'
?
'新建培训任务'
:
'编辑培训任务'
}
goBack=
{
handleGoBack
}
/>
...
@@ -93,7 +105,7 @@ function AddTrainTask() {
...
@@ -93,7 +105,7 @@ function AddTrainTask() {
<
BasicInfo
data=
{
basicInfo
}
onChange=
{
handleChangeBasicInfo
}
/>
<
BasicInfo
data=
{
basicInfo
}
onChange=
{
handleChangeBasicInfo
}
/>
</
TabPane
>
</
TabPane
>
<
TabPane
tab=
'2 培训内容'
key=
'TRAIN_CONTENT'
>
<
TabPane
tab=
'2 培训内容'
key=
'TRAIN_CONTENT'
>
<
TrainContent
/>
<
TrainContent
data=
{
taskList
}
onChange=
{
handleChangeTaskInfo
}
/>
</
TabPane
>
</
TabPane
>
</
Tabs
>
</
Tabs
>
</
div
>
</
div
>
...
...
src/modules/task-center/train-task/components/RelatedCourseDrawer.jsx
0 → 100644
View file @
bd6794c0
/*
* @Author: yuananting
* @Date: 2021-08-01 17:28:30
* @LastEditors: yuananting
* @LastEditTime: 2021-08-02 11:09:50
* @Description: 新建培训任务-关联课程抽屉
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import
React
,
{
Component
}
from
'react'
;
import
_
from
'underscore'
;
import
{
Radio
,
Tabs
,
Drawer
,
Input
,
message
,
Button
,
Tooltip
}
from
'antd'
;
import
{
PageControl
,
XMTable
}
from
'@/components'
;
import
college
from
'@/common/lottie/college'
;
import
CourseService
from
'@/domains/course-domain/CourseService'
;
import
User
from
'@/common/js/user'
;
import
Service
from
'@/common/js/service'
;
import
'./RelatedCourseDrawer.less'
;
const
{
Search
}
=
Input
;
const
{
TabPane
}
=
Tabs
;
class
RelatedCourseDrawer
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
// 直播课列表相关参数
liveDataSource
:
[],
liveSize
:
10
,
liveQuery
:
{
current
:
1
,
},
liveTotalCount
:
0
,
selectLive
:
[],
//弹窗内已选择的直播课程
currentLiveCourseListData
:
[],
//页面中已关联的直播课程
// 线上课列表相关参数(内外部课程)
videoCourseDivision
:
'internal'
,
videoDataSource
:
{
external
:
[],
internal
:
[],
},
videoSize
:
{
external
:
10
,
internal
:
10
,
},
videoSearchName
:
{
external
:
''
,
internal
:
''
,
},
videoSearchDefalt
:
''
,
videoQuery
:
{
external
:
{
current
:
1
,
},
internal
:
{
current
:
1
,
},
},
videoTotalCount
:
{
external
:
0
,
internal
:
0
,
},
selectVideo
:
{
external
:
[],
internal
:
[],
},
//弹窗内已选择的线上课程
currentVideoCourseListData
:
{
external
:
[],
internal
:
[],
},
//页面中已关联的线上课程
pictureDataSource
:
[],
pictureSize
:
10
,
pictureQuery
:
{
current
:
1
,
},
pictureTotalCount
:
0
,
selectPicture
:
[],
//弹窗内已选择的线上课程
currentPictureCourseListData
:
[],
//页面中已关联的线上课程
activeKey
:
'live'
,
currentTaskCourseData
:
[],
};
}
componentDidMount
()
{
this
.
handleFetchLiveDataList
();
this
.
handleFetchVideoDataList
();
this
.
handleFetchPictureDataList
();
}
// 获取直播课列表
handleFetchLiveDataList
=
()
=>
{
const
{
liveQuery
,
liveSize
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
let
currentLiveCourseListData
=
[];
_data
.
map
((
item
)
=>
{
item
.
courseList
.
map
((
childItem
,
childIndex
)
=>
{
if
(
childItem
.
courseType
===
'LIVE'
)
{
currentLiveCourseListData
.
push
(
childItem
.
courseId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
liveQuery
,
size
:
liveSize
,
excludeCourseIdList
:
currentLiveCourseListData
,
};
CourseService
.
getLiveCloudCourseBasePage
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
liveDataSource
:
records
,
liveTotalCount
:
Number
(
total
),
currentLiveCourseListData
,
});
});
};
// 获取线上课列表
handleFetchVideoDataList
=
()
=>
{
const
{
videoQuery
,
videoSize
,
videoDataSource
,
videoTotalCount
,
videoCourseDivision
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
let
currentVideoCourseListData
=
[];
_data
.
map
((
item
,
index
)
=>
{
item
.
courseList
.
map
((
childItem
,
childIndex
)
=>
{
if
(
childItem
.
courseType
===
'VOICE'
)
{
currentVideoCourseListData
.
push
(
childItem
.
courseId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
videoQuery
[
videoCourseDivision
],
size
:
videoSize
[
videoCourseDivision
],
courseDivision
:
videoCourseDivision
===
'internal'
?
'INTERNAL'
:
'EXTERNAL'
,
excludeCourseIdList
:
currentVideoCourseListData
,
};
CourseService
.
videoScheduleBasePage
(
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
videoDataSource
:
{
...
videoDataSource
,
[
videoCourseDivision
]:
records
,
},
videoTotalCount
:
{
...
videoTotalCount
,
[
videoCourseDivision
]:
Number
(
total
),
},
currentVideoCourseListData
,
});
});
};
// 获取图文课列表
handleFetchPictureDataList
=
()
=>
{
const
{
pictureQuery
,
pictureSize
}
=
this
.
state
;
const
_data
=
[...
this
.
props
.
data
];
let
currentPictureCourseListData
=
[];
_data
.
map
((
item
,
index
)
=>
{
item
.
courseList
.
map
((
childItem
,
childIndex
)
=>
{
if
(
childItem
.
courseType
===
'PICTURE'
)
{
currentPictureCourseListData
.
push
(
childItem
.
courseId
);
}
return
childItem
;
});
return
item
;
});
const
params
=
{
...
pictureQuery
,
size
:
pictureSize
,
courseType
:
'PICTURE'
,
storeId
:
User
.
getStoreId
(),
excludeCourseIdList
:
currentPictureCourseListData
,
};
Service
.
Hades
(
'public/hades/mediaCoursePage'
,
params
).
then
((
res
)
=>
{
const
{
result
=
{}
}
=
res
;
const
{
records
=
[],
total
=
0
}
=
result
;
this
.
setState
({
pictureDataSource
:
records
,
pictureTotalCount
:
Number
(
total
),
currentPictureCourseListData
,
});
});
};
handleChangVideoCourseName
=
(
value
)
=>
{
const
{
videoQuery
,
videoCourseDivision
,
videoSearchName
}
=
this
.
state
;
videoQuery
[
videoCourseDivision
].
courseName
=
value
;
videoQuery
[
videoCourseDivision
].
current
=
1
;
this
.
setState
({
...
videoQuery
,
videoSearchDefalt
:
value
,
videoSearchName
:
{
...
videoSearchName
,
[
videoCourseDivision
]:
value
,
},
});
};
handleChangLiveCourseName
=
(
value
)
=>
{
const
{
liveQuery
}
=
this
.
state
;
liveQuery
.
courseName
=
value
;
liveQuery
.
current
=
1
;
this
.
setState
({
liveQuery
,
});
};
handleChangPictureCourseName
=
(
value
)
=>
{
const
{
pictureQuery
}
=
this
.
state
;
pictureQuery
.
courseName
=
value
;
pictureQuery
.
current
=
1
;
this
.
setState
({
pictureQuery
,
});
};
onShowLiveSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
liveSize
:
size
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
};
onShowVideoSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
videoSize
:
size
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
};
onShowPictureSizeChange
=
(
current
,
size
)
=>
{
if
(
current
===
size
)
{
return
;
}
this
.
setState
(
{
pictureSize
:
size
,
},
()
=>
{
this
.
handleFetchPictureDataList
();
}
);
};
// 请求表头
parseCourseColumns
=
(
type
)
=>
{
const
columns
=
[
{
title
:
(
<
span
>
<
span
>
课程信息
</
span
>
<
Tooltip
title=
'仅显示未关联课程,已关联课程不支持重复选择'
>
<
i
className=
'icon iconfont'
style=
{
{
marginLeft
:
'5px'
,
cursor
:
'pointer'
,
color
:
'#bfbfbf'
,
fontSize
:
'14px'
,
fontWeight
:
'400'
}
}
>

</
i
>
</
Tooltip
>
</
span
>
),
key
:
'course'
,
dataIndex
:
'course'
,
width
:
'40%'
,
render
:
(
val
,
record
)
=>
{
if
(
type
===
'live'
)
{
let
hasCover
=
false
;
return
(
<
div
className=
'course-info'
>
{
record
.
courseMediaVOS
.
map
((
item
)
=>
{
if
(
item
.
contentType
===
'COVER'
)
{
hasCover
=
true
;
return
<
img
className=
'course-cover'
src=
{
item
.
mediaUrl
}
alt=
''
/>;
}
return
null
;
})
}
<
If
condition=
{
!
hasCover
}
>
<
img
className=
'course-cover'
src=
{
'https://image.xiaomaiketang.com/xm/Yip2YtFDwH.png'
}
alt=
''
/>
</
If
>
<
div
>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
{
/* <span
className='course-status'
style={{ color: courseStateShow[record.courseState].color, border: `1px solid ${courseStateShow[record.courseState].color}` }}>
{courseStateShow[record.courseState].title}
</span> */
}
</
div
>
</
div
>
);
}
else
{
const
{
coverUrl
}
=
record
;
return
(
<
div
className=
'course-info'
>
<
img
className=
'course-cover'
src=
{
coverUrl
||
(
type
===
'video'
?
'https://image.xiaomaiketang.com/xm/TwtGPQGE4K.png'
:
'https://image.xiaomaiketang.com/xm/wFnpZtp2yB.png'
)
}
alt=
''
/>
<
div
className=
'course-name'
>
{
record
.
courseName
}
</
div
>
</
div
>
);
}
},
},
type
===
'live'
?
{
title
:
'上课时间'
,
key
:
'courseTime'
,
dataIndex
:
'courseTime'
,
width
:
'40%'
,
render
:
(
val
,
record
)
=>
{
return
(
<
div
>
<
div
>
{
formatDate
(
'YYYY-MM-DD'
,
record
.
startTime
)
}
</
div
>
<
div
>
{
formatDate
(
'H:i'
,
record
.
startTime
)
}
~
{
formatDate
(
'H:i'
,
record
.
endTime
)
}
</
div
>
</
div
>
);
},
}
:
type
===
'video'
?
{
title
:
'课节数'
,
key
:
'courseChapterNum'
,
dataIndex
:
'courseChapterNum'
,
width
:
'20%'
,
align
:
'right'
,
render
:
(
val
,
record
)
=>
{
return
<
span
>
{
val
||
1
}
</
span
>;
},
}
:
{
title
:
'更新时间'
,
key
:
'updated'
,
dataIndex
:
'updated'
,
width
:
'25%'
,
render
:
(
val
,
record
)
=>
{
return
<
span
className=
'course-status'
>
{
formatDate
(
'YYYY-MM-DD'
,
record
.
updated
)
}
</
span
>;
},
},
{
title
:
'学院展示'
,
key
:
'shelfState'
,
dataIndex
:
'shelfState'
,
width
:
'20%'
,
render
:
(
val
,
record
)
=>
{
return
<
span
>
{
record
.
shelfState
===
'YES'
?
'开启'
:
'关闭'
}
</
span
>;
},
},
];
return
columns
;
};
selectLiveList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskCourseData
,
selectLive
,
selectPicture
}
=
this
.
state
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectLive
,
(
item
)
=>
item
.
liveCourseId
===
record
.
liveCourseId
))
{
_list
=
_
.
uniq
(
selectLive
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
liveCourseId
);
}
else
{
_list
=
_
.
reject
(
selectLive
,
(
item
)
=>
item
.
liveCourseId
===
record
.
liveCourseId
);
}
if
(
_list
.
length
+
currentTaskCourseData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectLive
:
_list
});
};
selectVideoList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskCourseData
,
selectLive
,
selectPicture
,
videoCourseDivision
}
=
this
.
state
;
let
{
[
videoCourseDivision
]:
selectList
}
=
selectVideo
;
let
otherVideoCourseDivision
=
videoCourseDivision
===
'internal'
?
'external'
:
'internal'
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectList
,
(
item
)
=>
item
.
id
===
record
.
id
))
{
_list
=
_
.
uniq
(
selectList
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectList
,
(
item
)
=>
item
.
id
===
record
.
id
);
}
if
(
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskCourseData
.
length
+
selectLive
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectVideo
:
{
...
selectVideo
,
[
videoCourseDivision
]:
_list
,
},
});
};
selectPictureList
=
(
record
,
selected
)
=>
{
const
{
selectVideo
,
currentTaskCourseData
,
selectLive
,
selectPicture
}
=
this
.
state
;
let
_list
=
[];
if
(
selected
||
!
_
.
find
(
selectPicture
,
(
item
)
=>
item
.
id
===
record
.
id
))
{
_list
=
_
.
uniq
(
selectPicture
.
concat
([
record
]),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectPicture
,
(
item
)
=>
item
.
id
===
record
.
id
);
}
if
(
_list
.
length
+
currentTaskCourseData
.
length
+
selectLive
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
return
;
}
this
.
setState
({
selectPicture
:
_list
});
};
clearSelectCourse
=
()
=>
{
this
.
setState
({
selectLive
:
[],
selectVideo
:
{
internal
:
[],
external
:
[],
},
selectPicture
:
[],
});
};
handleSelectVideo
=
(
selectVideo
)
=>
{
return
selectVideo
.
map
((
item
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
id
;
_item
.
courseType
=
'VOICE'
;
_item
.
courseName
=
item
.
courseName
;
_item
.
courseChapterNum
=
item
.
courseChapterNum
;
return
_item
;
});
};
handleSelectLive
=
(
selectLive
)
=>
{
return
selectLive
.
map
((
item
,
index
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
liveCourseId
;
_item
.
courseType
=
'LIVE'
;
_item
.
courseName
=
item
.
courseName
;
_item
.
courseState
=
item
.
courseState
;
return
_item
;
});
};
videoCourseDivisionChange
=
(
e
)
=>
{
const
{
videoSearchName
}
=
this
.
state
;
this
.
setState
(
{
videoCourseDivision
:
e
.
target
.
value
,
videoSearchDefalt
:
videoSearchName
[
e
.
target
.
value
],
},
()
=>
{
this
.
handleFetchVideoDataList
();
}
);
};
handleSelectPicture
=
(
selectPicture
)
=>
{
return
selectPicture
.
map
((
item
,
index
)
=>
{
let
_item
=
{};
_item
.
courseId
=
item
.
id
;
_item
.
courseType
=
'PICTURE'
;
_item
.
courseName
=
item
.
courseName
;
return
_item
;
});
};
renderFooter
=
()
=>
{
const
{
activeKey
}
=
this
.
state
;
let
href
=
''
;
switch
(
activeKey
)
{
case
'live'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-live-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的直播课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
case
'video'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-video-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的线上课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
case
'picture'
:
href
=
(
<
a
target=
'_blank'
rel=
'noopener noreferrer'
className=
'link-create-course'
href=
{
window
.
location
.
origin
+
window
.
location
.
pathname
+
'#/create-graphics-course?type=add'
}
onClick=
{
this
.
props
.
onClose
}
>
没有找到需要的图文课?
<
span
>
去创建
</
span
>
</
a
>
);
break
;
default
:
break
;
}
return
href
;
};
render
()
{
const
{
liveDataSource
,
liveSize
,
liveQuery
,
liveTotalCount
,
selectLive
,
videoDataSource
,
videoSize
,
videoQuery
,
videoSearchDefalt
,
videoTotalCount
,
selectVideo
,
currentTaskCourseData
,
selectPicture
,
pictureDataSource
,
pictureSize
,
pictureQuery
,
pictureTotalCount
,
videoCourseDivision
,
}
=
this
.
state
;
const
{
visible
}
=
this
.
props
;
return
(
<
Drawer
title=
'关联课程'
width=
{
720
}
maskClosable=
{
false
}
closable=
{
true
}
onClose=
{
this
.
props
.
onClose
}
visible=
{
visible
}
mask
className=
'related-course-drawer'
>
<
div
>
<
Tabs
type=
'line'
defaultActiveKey=
'live'
onChange=
{
(
activeKey
)
=>
{
this
.
setState
({
activeKey
:
activeKey
});
}
}
>
<
TabPane
tab=
'直播课'
key=
'live'
>
<
div
className=
'search-container'
>
<
Search
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangLiveCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchLiveDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskCourseData
.
length
}
个课程,可继续选择
{
20
-
currentTaskCourseData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
liveCourseId
}
dataSource=
{
liveDataSource
}
columns=
{
this
.
parseCourseColumns
(
'live'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectLive
,
'liveCourseId'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectLiveList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
if
(
selected
)
{
_list
=
_
.
uniq
(
selectLive
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
liveCourseId
);
}
else
{
_list
=
_
.
reject
(
selectLive
,
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
liveCourseId
===
item
.
liveCourseId
));
}
if
(
_list
.
length
+
currentTaskCourseData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
currentTaskCourseData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
+
selectPicture
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectLive
:
_list
});
},
}
}
/>
{
liveDataSource
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
liveQuery
.
current
-
1
}
pageSize=
{
liveSize
}
size=
'small'
total=
{
liveTotalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
liveQuery
,
current
:
page
+
1
};
this
.
setState
(
{
liveQuery
:
_query
,
},
()
=>
{
this
.
handleFetchLiveDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowLiveSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
<
TabPane
tab=
'线上课'
key=
'video'
>
<
Radio
.
Group
value=
{
videoCourseDivision
}
onChange=
{
this
.
videoCourseDivisionChange
}
style=
{
{
marginBottom
:
16
}
}
>
<
Radio
.
Button
value=
'internal'
>
内部课程
</
Radio
.
Button
>
<
Radio
.
Button
value=
'external'
>
外部课程
</
Radio
.
Button
>
</
Radio
.
Group
>
<
div
className=
'search-container'
>
<
Search
value=
{
videoSearchDefalt
}
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangVideoCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchVideoDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskCourseData
.
length
}
个课程,可继续选择
{
20
-
currentTaskCourseData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
videoDataSource
[
videoCourseDivision
]
}
columns=
{
this
.
parseCourseColumns
(
'video'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectVideo
[
videoCourseDivision
],
'id'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectVideoList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
let
otherVideoCourseDivision
=
videoCourseDivision
===
'internal'
?
'external'
:
'internal'
;
if
(
selected
)
{
_list
=
_
.
uniq
(
selectVideo
[
videoCourseDivision
].
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectVideo
[
videoCourseDivision
],
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
));
}
if
(
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskCourseData
.
length
+
selectLive
.
length
+
selectPicture
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
selectVideo
[
otherVideoCourseDivision
]?.
length
+
currentTaskCourseData
.
length
+
selectLive
.
length
+
selectPicture
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectVideo
:
{
...
selectVideo
,
[
videoCourseDivision
]:
_list
,
},
});
},
}
}
/>
{
videoDataSource
[
videoCourseDivision
].
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
videoQuery
[
videoCourseDivision
].
current
-
1
}
pageSize=
{
videoSize
[
videoCourseDivision
]
}
size=
'small'
total=
{
videoTotalCount
[
videoCourseDivision
]
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
videoQuery
[
videoCourseDivision
],
current
:
page
+
1
};
this
.
setState
(
{
videoQuery
:
{
...
videoQuery
,
[
videoCourseDivision
]:
_query
,
},
},
()
=>
{
this
.
handleFetchVideoDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowVideoSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
<
TabPane
tab=
'图文课'
key=
'picture'
>
<
div
className=
'search-container'
>
<
Search
enterButton=
{
<
span
className=
'icon iconfont'
>

</
span
>
}
placeholder=
'搜索课程名称'
style=
{
{
width
:
200
}
}
onChange=
{
(
e
)
=>
{
this
.
handleChangPictureCourseName
(
e
.
target
.
value
);
}
}
onSearch=
{
()
=>
{
this
.
handleFetchPictureDataList
();
}
}
/>
</
div
>
<
div
className=
'select-area'
>
<
div
className=
'select-box'
>
<
div
>
<
span
className=
'icon iconfont tip-icon'
>

</
span
>
<
span
className=
'select-num'
>
已选择
{
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
+
selectPicture
.
length
}
个
</
span
>
</
div
>
<
div
>
<
span
className=
'clear-btn'
onClick=
{
this
.
clearSelectCourse
}
>
清空
</
span
>
</
div
>
</
div
>
<
div
className=
'related-box'
>
该任务已关联
{
currentTaskCourseData
.
length
}
个课程,可继续选择
{
20
-
currentTaskCourseData
.
length
}
个
</
div
>
</
div
>
<
div
>
<
XMTable
renderEmpty=
{
{
image
:
college
,
description
:
'暂无数据'
,
}
}
rowKey=
{
(
record
)
=>
record
.
id
}
dataSource=
{
pictureDataSource
}
columns=
{
this
.
parseCourseColumns
(
'picture'
)
}
pagination=
{
false
}
bordered
rowSelection=
{
{
type
:
'checkbox'
,
selectedRowKeys
:
_
.
pluck
(
selectPicture
,
'id'
),
onSelect
:
(
record
,
selected
)
=>
{
this
.
selectPictureList
(
record
,
selected
);
},
onSelectAll
:
(
selected
,
_selectedRows
,
changeRows
)
=>
{
let
_list
=
[];
if
(
selected
)
{
_list
=
_
.
uniq
(
selectPicture
.
concat
(
changeRows
),
false
,
(
item
)
=>
item
.
id
);
}
else
{
_list
=
_
.
reject
(
selectPicture
,
(
item
)
=>
_
.
find
(
changeRows
,
(
data
)
=>
data
.
id
===
item
.
id
));
}
if
(
_list
.
length
+
currentTaskCourseData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
>
20
)
{
message
.
warning
(
'无法继续选择,一个任务最多关联20个课程'
);
const
extraLength
=
_list
.
length
+
currentTaskCourseData
.
length
+
selectVideo
.
internal
.
length
+
selectVideo
.
external
.
length
+
selectLive
.
length
-
20
;
_list
.
splice
(
_list
.
length
-
extraLength
,
extraLength
);
}
this
.
setState
({
selectPicture
:
_list
});
},
}
}
/>
{
pictureDataSource
.
length
>
0
&&
(
<
div
className=
'box-footer'
>
<
PageControl
current=
{
pictureQuery
.
current
-
1
}
pageSize=
{
pictureSize
}
size=
'small'
total=
{
pictureTotalCount
}
toPage=
{
(
page
)
=>
{
const
_query
=
{
...
pictureQuery
,
current
:
page
+
1
};
this
.
setState
(
{
pictureQuery
:
_query
,
},
()
=>
{
this
.
handleFetchPictureDataList
();
}
);
}
}
onShowSizeChange=
{
this
.
onShowPictureSizeChange
}
/>
</
div
>
)
}
</
div
>
</
TabPane
>
</
Tabs
>
</
div
>
<
div
className=
'footer shrink-footer'
>
<
Button
onClick=
{
this
.
props
.
onClose
}
>
取消
</
Button
>
<
Button
type=
'primary'
>
保存
</
Button
>
</
div
>
</
Drawer
>
);
}
}
export
default
RelatedCourseDrawer
;
src/modules/task-center/train-task/components/RelatedCourseDrawer.less
0 → 100644
View file @
bd6794c0
.related-course-drawer {
.link-create-course {
color: #666666;
font-size: 14px;
width: 638px;
text-align: left;
display: inline-block;
span {
color: #2966ff;
}
}
.search-container {
margin-bottom: 16px;
}
.select-area {
margin-bottom: 12px;
display: flex;
justify-content: space-between;
.select-box {
display: inline-box;
width: 186px;
background: #e9efff;
border-radius: 4px;
padding: 6px 16px;
margin-right: 8px;
display: flex;
justify-content: space-between;
.tip-icon {
color: #2966ff;
font-size: 14px;
margin-right: 4px;
}
.select-num {
color: #666666;
font-size: 14px;
}
.clear-btn {
text-align: right;
color: #2966ff;
font-size: 14px;
}
}
.related-box {
padding: 6px 16px;
background: #e9efff;
border-radius: 4px;
flex: 1;
color: #666666;
font-size: 14px;
}
}
.search-container {
margin-bottom: 16px;
}
.select-area {
margin-bottom: 12px;
display: flex;
justify-content: space-between;
.select-box {
display: inline-box;
width: 186px;
background: #e9efff;
border-radius: 4px;
padding: 6px 16px;
margin-right: 8px;
display: flex;
justify-content: space-between;
.tip-icon {
color: #2966ff;
font-size: 14px;
margin-right: 4px;
}
.select-num {
color: #666666;
font-size: 14px;
}
.clear-btn {
text-align: right;
color: #5289fa;
font-size: 14px;
}
}
.related-box {
padding: 6px 16px;
background: #e9efff;
border-radius: 4px;
flex: 1;
color: #666666;
font-size: 14px;
}
}
.course-info {
display: flex;
align-items: center;
.course-cover {
width: 97px;
height: 55px;
display: inline-block;
border-radius: 4px;
margin-right: 8px;
}
.course-name {
font-size: 14px;
color: #666;
text-overflow: -o-ellipsis-lastline;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
line-clamp: 2;
-webkit-box-orient: vertical;
width: 180px;
}
.course-status {
font-size: 12px;
line-height: 18px;
display: inline-block;
border-radius: 2px;
padding: 0 8px;
margin-top: 8px;
}
}
.footer {
position: fixed;
right: 0;
bottom: 0;
height: 50px;
width: 720px;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 24px;
background: #fff;
border-top: 1px solid #e8e8e8;
z-index: 9999;
.ant-btn {
margin-left: 8px;
}
}
}
src/modules/task-center/train-task/components/TrainContent.jsx
View file @
bd6794c0
...
@@ -2,27 +2,239 @@
...
@@ -2,27 +2,239 @@
* @Author: yuananting
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditors: yuananting
* @LastEditTime: 2021-0
7-30 16:58:03
* @LastEditTime: 2021-0
8-02 10:58:34
* @Description: 任务中心-培训任务-新建-培训内容
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
*/
import
React
from
'react'
;
import
React
,
{
Component
}
from
'react'
;
import
{
Form
,
Button
,
Input
,
Space
,
DatePicker
,
Radio
,
Tag
,
Col
,
message
,
Tooltip
}
from
'antd'
;
import
{
Form
,
Button
,
Input
,
Space
,
DatePicker
,
Radio
,
Tag
,
Col
,
message
,
Tooltip
,
Collapse
,
Dropdown
,
Menu
,
Drawer
}
from
'antd'
;
import
{
sortableContainer
,
sortableElement
,
sortableHandle
}
from
'react-sortable-hoc'
;
import
{
sortableContainer
,
sortableElement
,
sortableHandle
}
from
'react-sortable-hoc'
;
import
arrayMove
from
'array-move'
;
import
'./TrainContent.less'
;
import
RelatedCourseDrawer
from
'./RelatedCourseDrawer'
;
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
>);
class
TrainContent
extends
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
state
=
{
dataSource
:
props
.
data
,
showCourseDrawer
:
false
,
};
}
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
>
</
Menu
.
Item
>
<
Menu
.
Item
key=
'exam'
>
<
img
className=
'type-option-icon'
src=
'https://image.xiaomaiketang.com/xm/M4BEXnRWbb.png'
/>
<
span
>
考试
</
span
>
</
Menu
.
Item
>
<
Menu
.
Item
key=
'homework'
>
<
img
className=
'type-option-icon'
src=
'https://image.xiaomaiketang.com/xm/ypWQcFWnxB.png'
/>
<
span
>
实操作业
</
span
>
</
Menu
.
Item
>
</
Menu
>
);
};
onTaskSortEnd
=
({
oldIndex
,
newIndex
})
=>
{
const
{
dataSource
}
=
this
.
state
;
if
(
oldIndex
!==
newIndex
)
{
const
newData
=
arrayMove
([].
concat
(
dataSource
),
oldIndex
,
newIndex
).
filter
((
el
)
=>
!!
el
);
this
.
setState
(
{
dataSource
:
newData
,
},
()
=>
{
this
.
props
.
onChange
(
newData
);
}
);
}
};
handleRenameTaskName
=
(
e
,
item
)
=>
{
const
{
value
}
=
e
.
target
;
const
{
dataSource
}
=
this
.
state
;
item
.
taskName
=
value
;
this
.
setState
(
{
dataSource
,
},
()
=>
{
this
.
props
.
onChange
(
dataSource
);
}
);
};
handleTaskNameBlur
=
(
e
,
item
)
=>
{
const
{
value
}
=
e
.
target
;
const
{
dataSource
}
=
this
.
state
;
let
input
=
/^
[\s]
*$/
;
if
(
value
&&
!
input
.
test
(
value
))
{
item
.
type
=
'text'
;
this
.
setState
(
{
dataSource
,
},
()
=>
{
this
.
props
.
onChange
(
dataSource
);
}
);
}
};
handleValidatorTaskName
=
(
rule
,
value
)
=>
{
let
input
=
/^
[\s]
*$/
;
if
(
input
.
test
(
value
)
||
!
value
)
{
return
Promise
.
reject
(
new
Error
(
'请输入任务名称'
));
}
return
Promise
.
resolve
();
};
renderTaskInfo
=
(
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> */
}
<
Form
>
<
Form
.
Item
initialValue=
{
item
.
taskName
}
validateTrigger=
{
[
'onChange'
,
'onBlur'
]
}
name=
{
[
'taskName'
]
}
rules=
{
[
{
validator
:
(
rule
,
value
)
=>
this
.
handleValidatorTaskName
(
rule
,
value
),
},
]
}
>
<
Input
className=
'task-name-input'
style=
{
{
width
:
300
}
}
placeholder=
'请输入阶段名称'
maxLength=
{
20
}
onChange=
{
(
e
)
=>
{
this
.
handleRenameTaskName
(
e
,
item
);
e
.
stopPropagation
();
}
}
onBlur=
{
(
e
)
=>
{
this
.
handleTaskNameBlur
(
e
,
item
);
e
.
stopPropagation
();
}
}
/>
</
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
>
<
span
className=
'item-operate'
>
<
span
className=
'operate__item'
onClick=
{
(
e
)
=>
{
const
{
dataSource
}
=
this
.
state
;
item
.
type
=
'input'
;
this
.
setState
({
dataSource
});
e
.
stopPropagation
();
}
}
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'text'
>
重命名
</
span
>
</
span
>
<
span
className=
'operate__item'
style=
{
{
marginLeft
:
16
}
}
onClick=
{
(
e
)
=>
{
this
.
handleDeleteTask
(
index
);
e
.
stopPropagation
();
}
}
>
<
span
className=
'icon iconfont'
>

</
span
>
<
span
className=
'text'
>
删除
</
span
>
</
span
>
</
span
>
<
DragHandle
/>
</
div
>
);
};
renderTaskItem
=
(
item
,
index
)
=>
{
return
(
<
Collapse
ghost
>
<
Panel
header=
{
this
.
renderTaskInfo
(
item
,
index
)
}
key=
{
index
}
>
{
/* {renderTaskItem(props.iteminfo, props.index)} */
}
<
Dropdown
overlay=
{
this
.
setTrianTypeOption
()
}
className=
'add-course-btn'
onClick=
{
()
=>
{
// this.showRelatedCourseModal(index);
}
}
>
<
span
>
+ 关联课程
</
span
>
</
Dropdown
>
</
Panel
>
</
Collapse
>
);
};
// 添加阶段
addStage
=
()
=>
{
const
{
dataSource
}
=
this
.
state
;
const
taskObj
=
{
taskName
:
''
,
index
:
dataSource
.
length
,
type
:
'input'
,
open
:
true
,
courseList
:
[],
};
const
newData
=
[...
dataSource
,
taskObj
];
this
.
setState
(
{
dataSource
:
newData
,
},
()
=>
{
this
.
props
.
onChange
(
newData
);
}
);
};
onCloseCourseDrawer
=
()
=>
{
this
.
setState
({
showCourseDrawer
:
false
,
});
};
function
TrainContent
(
props
)
{
render
()
{
const
SortableTaskContainer
=
sortableContainer
((
props
)
=>
<
div
{
...
props
}
></
div
>);
const
{
dataSource
,
showCourseDrawer
}
=
this
.
state
;
return
(
return
(
<
div
className=
'train-content__warp'
>
<
div
className=
'train-content__warp'
>
<
SortableTaskContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
this
.
onTaskSortEnd
}
>
<
SortableTaskContainer
useDragHandle
disableAutoscroll
helperClass=
'row-dragging'
onSortEnd=
{
this
.
onTaskSortEnd
}
className=
'plan-task-sort-container'
>
{
dataSource
.
map
((
item
,
index
)
=>
(
{
dataSource
.
map
((
item
,
index
)
=>
(
<
SortableTaskItem
taskitem=
{
this
.
renderTaskItem
(
item
,
index
)
}
index=
{
index
}
key=
{
index
}
></
SortableTaskItem
>
<
SortableTaskItem
taskitem=
{
this
.
renderTaskItem
(
item
,
index
)
}
index=
{
index
}
key=
{
index
}
></
SortableTaskItem
>
))
}
))
}
</
SortableTaskContainer
>
</
SortableTaskContainer
>
<
div
className=
'add-task-btn'
onClick=
{
()
=>
this
.
addStage
()
}
>
</
div
>
+ 添加阶段
);
</
div
>
<
RelatedCourseDrawer
data=
{
dataSource
}
onClose=
{
this
.
onCloseCourseDrawer
}
visible=
{
showCourseDrawer
}
/>
</
div
>
);
}
}
}
export
default
TrainContent
;
export
default
TrainContent
;
src/modules/task-center/train-task/components/TrainContent.less
0 → 100644
View file @
bd6794c0
.train-content__warp {
.ant-collapse-content {
padding-left: 24px !important;
}
}
.sort-task-item {
width: calc(100% - 24px);
display: inline-flex;
align-items: center;
.ant-form-item {
margin-bottom: 0 !important;
}
.item-name {
color: #333333;
}
.item-operate {
display: none;
margin-left: 30px;
.operate__item {
cursor: pointer;
.icon {
color: #bfbfbf;
font-size: 14px;
}
.text {
color: #666666;
margin-left: 8px;
}
}
}
&:hover {
.item-operate {
display: block;
}
}
.drag-btn {
margin-left: auto;
}
}
.add-course-btn {
color: #2966ff;
}
.add-task-btn {
color: #2966ff;
height: 52px;
background: #f7f8f9;
border-radius: 2px;
padding: 16px;
margin-top: 16px;
cursor: pointer;
}
.type-option-icon {
width: 20px;
height: 20px;
margin-right: 12px;
}
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