Commit bd6794c0 by yuananting

feat:添加培训内容部分

parent 52a7b420
@font-face {
font-family: 'iconfont'; /* Project id 2223403 */
src: url('//at.alicdn.com/t/font_2223403_oe5p510553.woff2?t=1624259078391') format('woff2'),
url('//at.alicdn.com/t/font_2223403_oe5p510553.woff?t=1624259078391') format('woff'),
url('//at.alicdn.com/t/font_2223403_oe5p510553.ttf?t=1624259078391') format('truetype');
src: url('//at.alicdn.com/t/font_2223403_e1xgcyaur7.woff2?t=1627810786858') format('woff2'),
url('//at.alicdn.com/t/font_2223403_e1xgcyaur7.woff?t=1627810786858') format('woff'),
url('//at.alicdn.com/t/font_2223403_e1xgcyaur7.ttf?t=1627810786858') format('truetype');
}
.iconfont {
font-family: 'iconfont' !important;
......
......@@ -8,30 +8,30 @@
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link rel="icon" href="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="小麦企学院,一站式企业培训数字化服务商,通过“工具+内容”,帮助企业快速从0到1搭建数字化培训体系,并让整个培训过程可视化,降低培训成本,提升培训效率。"
/>
<meta
name="keywords"
content="小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,素材库,培训课程,培训任务,直播课,线上课,图文课,线下活动,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂"
/>
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.png" /> -->
<link rel="shortcut icon" href="https://image.xiaomaiketang.com/xm/c4KiP2epBP.png" />
<head>
<meta charset="utf-8" />
<link rel="icon" href="" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="小麦企学院,一站式企业培训数字化服务商,通过“工具+内容”,帮助企业快速从0到1搭建数字化培训体系,并让整个培训过程可视化,降低培训成本,提升培训效率。"
/>
<meta
name="keywords"
content="小麦企学院,企业培训,员工培训,企业大学,企业内训,企业外训,培训计划,培训素材,企培,企训,素材库,培训课程,培训任务,直播课,线上课,图文课,线下活动,知识库,作业,考试,排行榜,培训类别管理,定制培训计划,管理数据,学习数据,企学院,资料共享,培训数字化,数字化培训,培训工具,在线培训,线上培训,培训saas,培训管理,企业微信培训,对客培训,客户培训,直播培训,互联网培训,新员工培训,管理培训,管理者培训,工人培训,制造业培训,餐饮培训,服务业培训,零售培训,门店培训,工厂培训,车间培训,培训补贴,人事培训,财务培训,职场培训,企业学院平台,教育企业学院,教育企业平台,教育平台学院,企业学习,酷学院,小鹅通,企业学院,云学堂,时代光华,云课堂,魔学院,云大学,米知云,授课学堂"
/>
<!-- <link rel="apple-touch-icon" href="../src/common/images/logo.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
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_oe5p510553.css" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2223403_e1xgcyaur7.css" />
<!--
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
......@@ -40,19 +40,19 @@
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`.
-->
<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/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/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" src="https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<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/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/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" src="https://xiaomai-js.oss-cn-hangzhou.aliyuncs.com/loghub-xm-0.0.1-beta.js"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
......@@ -62,5 +62,5 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</body>
</html>
......@@ -2,7 +2,7 @@
* @Author: yuananting
* @Date: 2021-07-29 13:57:03
* @LastEditors: yuananting
* @LastEditTime: 2021-07-30 16:35:59
* @LastEditTime: 2021-08-02 10:42:28
* @Description: 任务中心-培训任务-新建页面
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
......@@ -38,10 +38,18 @@ const DEFAULT_BASIC_INFO = {
percentCompletePicture: 100,
};
const DEFAULT_TASK_LIST = [
{
taskName: '阶段一',
courseList: [],
},
];
function AddTrainTask() {
const type = getParameterByName('type');
const [activeStep, setActiveStep] = useState('BASIC_INFO');
const [basicInfo, setBasicInfo] = useState(DEFAULT_BASIC_INFO);
const [taskList, setTaskList] = useState(DEFAULT_TASK_LIST);
function renderFooter() {
return (
......@@ -81,6 +89,10 @@ function AddTrainTask() {
});
}
function handleChangeTaskInfo(value) {
setTaskList(value);
}
return (
<div className='page add-train-task'>
<Breadcrumbs navList={type == 'add' ? '新建培训任务' : '编辑培训任务'} goBack={handleGoBack} />
......@@ -93,7 +105,7 @@ function AddTrainTask() {
<BasicInfo data={basicInfo} onChange={handleChangeBasicInfo} />
</TabPane>
<TabPane tab='2 培训内容' key='TRAIN_CONTENT'>
<TrainContent />
<TrainContent data={taskList} onChange={handleChangeTaskInfo} />
</TabPane>
</Tabs>
</div>
......
.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;
}
}
}
......@@ -2,27 +2,239 @@
* @Author: yuananting
* @Date: 2021-07-30 16:33:58
* @LastEditors: yuananting
* @LastEditTime: 2021-07-30 16:58:03
* @LastEditTime: 2021-08-02 10:58:34
* @Description: 任务中心-培训任务-新建-培训内容
* @Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import { Form, Button, Input, Space, DatePicker, Radio, Tag, Col, message, Tooltip } from 'antd';
import React, { Component } from 'react';
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 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'>&#xe6f5;</span>
<span className='text'>重命名</span>
</span>
<span
className='operate__item'
style={{ marginLeft: 16 }}
onClick={(e) => {
this.handleDeleteTask(index);
e.stopPropagation();
}}>
<span className='icon iconfont'>&#xe6f6;</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) {
const SortableTaskContainer = sortableContainer((props) => <div {...props}></div>);
return (
<div className='train-content__warp'>
<SortableTaskContainer useDragHandle disableAutoscroll helperClass='row-dragging' onSortEnd={this.onTaskSortEnd} className='plan-task-sort-container'>
{dataSource.map((item, index) => (
<SortableTaskItem taskitem={this.renderTaskItem(item, index)} index={index} key={index}></SortableTaskItem>
))}
</SortableTaskContainer>
</div>
);
render() {
const { dataSource, showCourseDrawer } = 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>
<RelatedCourseDrawer data={dataSource} onClose={this.onCloseCourseDrawer} visible={showCourseDrawer} />
</div>
);
}
}
export default TrainContent;
.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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment