Commit 1bf6cc7a by guomingpang

style:表格中的滑动开关使用small 型号

parent 7b685e7a
......@@ -125,7 +125,7 @@ class LiveCourseList extends React.Component {
columns = [
{
title: '直播课',
width: '23%',
key: 'course',
fixed: 'left',
dataIndex: 'courseName',
......@@ -284,6 +284,7 @@ class LiveCourseList extends React.Component {
render: (val, item, index) => {
return (
<Switch
size='small'
checked={item.shelfState === 'YES'}
defaultChecked={item.shelfState === 'YES' ? true : false}
onChange={(checked) => this.changeShelfState(index, item, checked)}
......
......@@ -9,7 +9,7 @@
import User from '@/common/js/user';
import college from '@/common/lottie/college';
import { PageControl, XMTable } from '@/components';
import { appId, LIVE_SHARE } from '@/domains/course-domain/constants';
import { LIVE_SHARE } from '@/domains/course-domain/constants';
import CourseService from '@/domains/course-domain/CourseService';
import ShareLiveModal from '@/modules/course-manage/modal/ShareLiveModal';
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
......@@ -57,7 +57,7 @@ class GraphicsCourseList extends React.Component {
handlePlanName = (planArray) => {
let planStr = '';
planArray.map((item, index) => {
planArray.forEach((item, index) => {
if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、';
} else {
......@@ -76,18 +76,21 @@ class GraphicsCourseList extends React.Component {
width: 321,
fixed: 'left',
render: (val, record) => {
const { coverUrl, scheduleVideoUrl } = record;
const { coverUrl } = record;
return (
<div className='record__item'>
{/* 上传了封面的话就用上传的封面, 没有的话就取视频的第一帧 */}
<img className='course-cover' src={coverUrl || defaultCoverUrl} />
{record.courseName.length > 25 ? (
<Tooltip title={record.courseName}>
<img className='course-cover' src={coverUrl || defaultCoverUrl} alt='' />
<Choose>
<When condition={record.courseName.length > 25}>
<Tooltip title={record.courseName}>
<div className='course-name'>{record.courseName}</div>
</Tooltip>
</When>
<Otherwise>
<div className='course-name'>{record.courseName}</div>
</Tooltip>
) : (
<div className='course-name'>{record.courseName}</div>
)}
</Otherwise>
</Choose>
</div>
);
},
......@@ -144,12 +147,14 @@ class GraphicsCourseList extends React.Component {
width: 120,
dataIndex: 'courseware',
render: (val, item, index) => {
return (
<Switch
checked={item.shelfState === "YES"}
defaultChecked={item.shelfState==="YES"?true:false}
onChange={(checked)=>this.changeShelfState(index,item,checked)}/>
)
return (
<Switch
size='small'
checked={item.shelfState === 'YES'}
defaultChecked={item.shelfState === 'YES' ? true : false}
onChange={(checked) => this.changeShelfState(index, item, checked)}
/>
);
},
},
{
......@@ -168,7 +173,7 @@ class GraphicsCourseList extends React.Component {
dataIndex: 'created',
sorter: true,
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val);
return window.formatDate('YYYY-MM-DD H:i', val);
},
},
{
......@@ -178,7 +183,7 @@ class GraphicsCourseList extends React.Component {
dataIndex: 'updated',
sorter: true,
render: (val) => {
return formatDate('YYYY-MM-DD H:i', val);
return window.formatDate('YYYY-MM-DD H:i', val);
},
},
{
......@@ -189,19 +194,22 @@ class GraphicsCourseList extends React.Component {
render: (val, record) => {
return (
<div className='related-task'>
{record.relatedPlanList ? (
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => {
return (
<span>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}{' '}
</span>
);
})}
</Tooltip>
) : (
<span></span>
)}
<Choose>
<When condition={record.relatedPlanList}>
<Tooltip title={this.handlePlanName(record.relatedPlanList)} placement='top' arrowPointAtCenter>
{record.relatedPlanList.map((item, index) => {
return (
<span>
{item.planName} {index < record.relatedPlanList.length - 1 && <span></span>}{' '}
</span>
);
})}
</Tooltip>
</When>
<Otherwise>
<span></span>
</Otherwise>
</Choose>
</div>
);
},
......@@ -297,7 +305,7 @@ class GraphicsCourseList extends React.Component {
className='operate__item'
key='edit'
onClick={() => {
RCHistory.push(`/create-graphics-course?type=edit&id=${item.id}`);
window.RCHistory.push(`/create-graphics-course?type=edit&id=${item.id}`);
}}>
编辑
</div>
......@@ -305,17 +313,17 @@ class GraphicsCourseList extends React.Component {
删除
</div>
</div>
)
}
//改变上架状态
changeShelfState = (index,item,checked) =>{
let _shelfState = checked ? "YES" : "NO"
);
};
//改变上架状态
changeShelfState = (index, item, checked) => {
let _shelfState = checked ? 'YES' : 'NO';
// if(_shelfState==='NO'){
// _shelfState = "YES";
// }else{
// _shelfState = "NO"
// }
const params={
const params = {
courseId: item.id,
shelfState: _shelfState,
};
......@@ -326,7 +334,7 @@ class GraphicsCourseList extends React.Component {
} else {
message.success('已取消展示');
}
this.props.changeShelfState(index,_shelfState)
this.props.changeShelfState(index, _shelfState);
}
});
};
......@@ -355,8 +363,6 @@ class GraphicsCourseList extends React.Component {
// 显示分享弹窗
handleShowShareModal = (record, needStr = false) => {
const { id, scheduleVideoUrl } = record;
const _appId = appId;
const htmlUrl = `${LIVE_SHARE}graphics_detail/${id}?id=${User.getStoreId()}`;
const longUrl = htmlUrl;
const { coverUrl, courseName } = record;
......
......@@ -8,80 +8,65 @@
*/
import React from 'react';
import {
Button,
Input,
Radio,
message,
Modal,
TreeSelect,
Select,
Switch,
TimePicker,
InputNumber,
Tooltip,
} from 'antd';
import { Button, Input, Radio, message, Modal, TreeSelect, Select, Switch, TimePicker, InputNumber, Tooltip } from 'antd';
import $ from 'jquery';
import RangePicker from "@/modules/common/DateRangePicker";
import ShowTips from "@/components/ShowTips";
import Breadcrumbs from "@/components/Breadcrumbs";
import SelectStudent from '../modal/select-student';
import Bus from '@/core/bus';
import RangePicker from '@/modules/common/DateRangePicker';
import ShowTips from '@/components/ShowTips';
import Breadcrumbs from '@/components/Breadcrumbs';
import SelectPrepareFileModal from '../../prepare-lesson/modal/SelectPrepareFileModal';
import PreviewOfflineModal from './modal/PreviewOfflineModal';
import StoreService from "@/domains/store-domain/storeService";
import StoreService from '@/domains/store-domain/storeService';
import Service from '@/common/js/service';
import { randomString } from '@/domains/basic-domain/utils';
import User from '@/common/js/user';
import _ from "underscore";
import _ from 'underscore';
import moment from 'moment';
import Upload from '@/core/upload';
import GraphicsEditor from '../components/GraphicsEditor';
import MultipleDatePicker from '@/components/MultipleDatePicker';
import ImgClipModal from '@/components/ImgClipModal'
import ImgClipModal from '@/components/ImgClipModal';
import './AddOfflineCourse.less';
const { Option } = Select;
const defaultCoverUrl = 'https://image.xiaomaiketang.com/xm/pxbWKsYA87.png';
let cutFlag = false;
const unitList = [
{ key: 'HOUR', value: '小时' },
{ key: 'MINUTE', value: '分钟' },
]
];
class AddOfflineCourse extends React.Component {
constructor(props) {
super(props);
const courseId = getParameterByName("id");
const pageType = getParameterByName("type");
const courseId = window.getParameterByName('id');
const pageType = window.getParameterByName('type');
this.state = {
courseId, // 线下课ID,编辑的时候从URL上带过来
pageType, // 页面类型: add->新建 edit->编辑
imageFile: null, // 需要被截取的图片
courseName: null, // 线下课名称
courseId, // 线下课ID,编辑的时候从URL上带过来
pageType, // 页面类型: add->新建 edit->编辑
imageFile: null, // 需要被截取的图片
courseName: null, // 线下课名称
courseMedia: '',
introduce: '',
coverId: null, // 线下封面的recourceId
coverUrl: defaultCoverUrl, // 线下课封面
studentList: [], // 上课学员列表
diskList: [], // 机构可见磁盘目录
selectedFileList: [], // 已经从资料云盘中勾选的文件
showCutModal: false, // 是否显示截图弹窗
coverId: null, // 线下封面的recourceId
coverUrl: defaultCoverUrl, // 线下课封面
studentList: [], // 上课学员列表
diskList: [], // 机构可见磁盘目录
selectedFileList: [], // 已经从资料云盘中勾选的文件
showCutModal: false, // 是否显示截图弹窗
studentModal: false,
categoryName:null, //分类名称
categoryName: null, //分类名称
categoryList: [],
courseCatalogList:[], //分类列表
categoryId:null, //分类的Id值
courseCatalogList: [], //分类列表
categoryId: null, //分类的Id值
whetherVisitorsJoin: 'NO', // 是否允许游客加入
isContent: true,
teacherList: [],
teacherQuery: {
size: 15,
current: 1,
nickName:null
nickName: null,
},
calendarTime: [],
offlineCourseType: 'ALL_DAY_OFFLINE',
......@@ -101,7 +86,7 @@ class AddOfflineCourse extends React.Component {
isEditDisablie: false,
startTime: new Date().getTime() + 300000, // 批量开始时分
endTime: new Date().getTime() + 300000, // 批量结束时分
}
};
}
componentWillMount() {
......@@ -114,27 +99,27 @@ class AddOfflineCourse extends React.Component {
}
initBus = () => {
Bus.bind('offlineEditorImage', this.uploadImage)
}
Bus.bind('offlineEditorImage', this.uploadImage);
};
removeBus = () => {
Bus.unbind('offlineEditorImage', this.uploadImage)
}
Bus.unbind('offlineEditorImage', this.uploadImage);
};
uploadImage = () => {
this.setState({ showSelectImageModal: true })
}
this.setState({ showSelectImageModal: true });
};
//获取分类列表
getCourseCatalogList = ()=>{
getCourseCatalogList = () => {
Service.Hades('public/hades/queryCategoryTree', { source: 0, tenantId: User.getStoreId(), count: false, userId: User.getUserId() }).then((res) => {
const { categoryList = [] } = res.result;
this.setState({
categoryList,
courseCatalogList: this.renderTreeNodes(categoryList),
})
});
});
}
};
renderTreeNodes = (data) => {
let newTreeData = data.map((item) => {
......@@ -151,22 +136,21 @@ class AddOfflineCourse extends React.Component {
checkDetail = (courseId) => {
return Service.Hades('public/hades/getOfflineCourseDetail', {
courseId
courseId,
}).then((res) => {
const { courseState } = res.result;
return courseState === 'UN_START';
});
}
};
// 获取线下课详情
handleFetchScheudleDetail = (courseId) => {
return Service.Hades('public/hades/getOfflineCourseDetail',{
courseId
return Service.Hades('public/hades/getOfflineCourseDetail', {
courseId,
}).then((res) => {
const { result = {} } = res || {};
const {
courseName,
courseState,
categoryId,
offlinePlace,
whetherVisitorsJoin,
......@@ -197,25 +181,25 @@ class AddOfflineCourse extends React.Component {
let coverId;
let coverUrl = this.state.coverUrl;
let hasIntro = false;
courseMediaVOS.map((item) => {
switch (item.contentType){
case "COVER":
switch (item.contentType) {
case 'COVER':
coverId = item.mediaContent;
coverUrl = item.mediaUrl;
break;
case "SCHEDULE":
break;
case 'SCHEDULE':
this.getTextDetail('courseMedia', item.mediaUrl);
break;
case "INTRO":
case 'INTRO':
hasIntro = true;
this.getTextDetail('introduce', item.mediaUrl);
break;
break;
default:
break;
}
return item;
})
});
this.setState({
loadintroduce: !hasIntro,
coverId,
......@@ -248,50 +232,43 @@ class AddOfflineCourse extends React.Component {
signOutType,
isEditDisablie: whetherHaveApply === 'YES',
});
})
}
});
};
getTextDetail = (key, url) => {
$.ajax({
data: {},
type: 'GET',
url,
contentType:'application/x-www-form-urlencoded; charset=UTF-8',
contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
success: (res) => {
this.setState({ [key]: res, [`load${key}`]: true });
}
})
}
},
});
};
handleGoBack = () => {
const {
coverId,
videoName,
videoDuration,
courseName,
categoryId,
whetherVisitorsJoin
} = this.state;
if(videoName || videoDuration || categoryId || courseName || coverId || whetherVisitorsJoin !== whetherVisitorsJoin ){
const { coverId, videoName, videoDuration, courseName, categoryId, whetherVisitorsJoin } = this.state;
if (videoName || videoDuration || categoryId || courseName || coverId || whetherVisitorsJoin !== whetherVisitorsJoin) {
Modal.confirm({
title: '确认要返回吗?',
content: '返回后,本次编辑的内容将不被保存。',
okText: '确认返回',
cancelText: '留在本页',
icon: <span className="icon iconfont default-confirm-icon">&#xe6f4;</span>,
icon: <span className='icon iconfont default-confirm-icon'>&#xe6f4;</span>,
onOk: () => {
window.RCHistory.push({
pathname: `/offline-course`,
});
}
},
});
}else{
} else {
window.RCHistory.push({
pathname: `/offline-course`,
});
}
}
};
// 显示预览弹窗
handleShowPreviewModal = () => {
const {
......@@ -339,68 +316,69 @@ class AddOfflineCourse extends React.Component {
signOutStartTimeNum,
signOutStartTimeUnit,
signOutEndTimeNum,
signOutEndTimeUnit,
}
signOutEndTimeUnit,
};
const previewOfflineModal = (
<PreviewOfflineModal
data={data}
close={() => {
this.setState({
previewOfflineModal: null
})
previewOfflineModal: null,
});
}}
/>
);
this.setState({ previewOfflineModal });
}
};
handleSelectCover = (file)=> {
handleSelectCover = (file) => {
this.setState({
visible: true,
imageFile:file
imageFile: file,
});
}
};
//获取resourceId
getSignature = (blob, fileName) => {
Upload.uploadBlobToOSS(blob, 'cover' + (new Date()).valueOf(),null,'signInfo').then((signInfo) => {
this.setState({
coverClicpPath:signInfo.fileUrl,
coverId:signInfo.resourceId,
visible: false
},()=>this.updateCover())
Upload.uploadBlobToOSS(blob, 'cover' + new Date().valueOf(), null, 'signInfo').then((signInfo) => {
this.setState(
{
coverClicpPath: signInfo.fileUrl,
coverId: signInfo.resourceId,
visible: false,
},
() => this.updateCover()
);
});
};
updateCover = () =>{
const {coverClicpPath,coverId} = this.state
updateCover = () => {
const { coverClicpPath, coverId } = this.state;
this.setState({
showSelectCoverModal: false,
coverUrl:coverClicpPath,
coverId:coverId
})
}
coverUrl: coverClicpPath,
coverId: coverId,
});
};
preSubmit = () => {
//过期判断
if (User.getExpirationTime() && moment().valueOf() > Number(User.getExpirationTime())) {
Modal.warning({
title:"服务已到期",
content: "当前企业购买的小麦企学院服务已到期,如需继续使用学院功能,请尽快续费购买",
okText: "我知道了"
})
return
title: '服务已到期',
content: '当前企业购买的小麦企学院服务已到期,如需继续使用学院功能,请尽快续费购买',
okText: '我知道了',
});
return;
}
const { courseId } = this.state;
if (courseId) {
this.checkDetail(courseId).then(bool => bool ? this.handleSubmit() : message.warning('课程已开始,无法继续编辑'))
this.checkDetail(courseId).then((bool) => (bool ? this.handleSubmit() : message.warning('课程已开始,无法继续编辑')));
} else {
this.handleSubmit();
}
}
};
// 保存
handleSubmit = () => {
......@@ -436,20 +414,20 @@ class AddOfflineCourse extends React.Component {
isMore,
} = this.state;
let coverObj ={
contentType:'COVER',
let coverObj = {
contentType: 'COVER',
mediaContent: coverId,
mediaType:'PICTURE',
mediaType: 'PICTURE',
mediaUrl: coverUrl,
}
};
let scheduleMediaRequests = [];
if(coverId){
scheduleMediaRequests = [coverObj]
if (coverId) {
scheduleMediaRequests = [coverObj];
}
// 编辑且使用默认图时不传
if (pageType === 'edit' && coverUrl === defaultCoverUrl) {
scheduleMediaRequests = []
scheduleMediaRequests = [];
}
const commonParams = {
categoryId,
......@@ -494,16 +472,21 @@ class AddOfflineCourse extends React.Component {
// 校验必填字段:课程名称, 课程线下
this.handleValidate(commonParams).then((res) => {
if (!res) return;
Upload.uploadTextToOSS(introduce, `${randomString()}.txt`, (introduceId) => {
this.submitRemote({
courseId,
pageType,
commonParams,
introduceId,
});
}, () => message.warning('上传课程简介失败'));
Upload.uploadTextToOSS(
introduce,
`${randomString()}.txt`,
(introduceId) => {
this.submitRemote({
courseId,
pageType,
commonParams,
introduceId,
});
},
() => message.warning('上传课程简介失败')
);
});
}
};
submitRemote = (data) => {
const { courseId, pageType, commonParams, introduceId } = data;
......@@ -511,65 +494,68 @@ class AddOfflineCourse extends React.Component {
if (pageType === 'add') {
Service.Hades('public/hades/createOfflineCourse', commonParams).then((res) => {
if (!res) return;
message.success("新建成功");
message.success('新建成功');
window.RCHistory.push({
pathname: `/offline-course`,
});
})
});
} else {
const editParams = {
courseId:courseId,
courseId: courseId,
...commonParams,
}
};
Service.Hades('public/hades/updateOfflineCourse', editParams).then((res) => {
if (!res) return;
message.success("保存成功");
message.success('保存成功');
window.RCHistory.push({
pathname: `/offline-course`,
});
});
}
}
};
handleValidate = (data) => {
return new Promise((resolve) => {
if (!data.courseName) {
message.warning('请输入课程名称');
resolve(false);
} else if(!data.categoryId){
} else if (!data.categoryId) {
message.warning('请选择课程分类');
resolve(false);
} else if(!data.offlinePlace){
} else if (!data.offlinePlace) {
message.warning('请输入上课地点');
resolve(false);
} else if(!data.teacherId ){
} else if (!data.teacherId) {
message.warning('请选择讲师');
resolve(false);
} else if(_.isEmpty(data.calendarTime)){
} else if (_.isEmpty(data.calendarTime)) {
message.warning('请选择上课日期');
resolve(false);
} else if(!data.startTime || !data.endTime){
} else if (!data.startTime || !data.endTime) {
message.warning('请选择上课时间');
resolve(false);
} else if(moment(moment(data.calendarTime[0]).format('YYYY-MM-DD') + moment(data.startTime).format(' HH:mm')).valueOf() < Date.now()){
} else if (moment(moment(data.calendarTime[0]).format('YYYY-MM-DD') + moment(data.startTime).format(' HH:mm')).valueOf() < Date.now()) {
message.warning('上课时间不能早于现在');
resolve(false);
} else if(data.startTime >= data.endTime){
} else if (data.startTime >= data.endTime) {
message.warning('上课结束时间不能早于上课开始时间');
resolve(false);
} else if(data.whetherSetApply === 'YES' && !data.startTimeApply){
} else if (data.whetherSetApply === 'YES' && !data.startTimeApply) {
message.warning('请选择报名时间');
resolve(false);
} else if(data.whetherSetApply === 'YES' && data.startTimeApply >= data.endTimeApply){
} else if (data.whetherSetApply === 'YES' && data.startTimeApply >= data.endTimeApply) {
message.warning('报名结束时间需大于报名开始时间');
resolve(false);
} else if(data.whetherSetApply === 'YES' && data.endTimeApply > moment(moment(data.calendarTime[0]).format('YYYY-MM-DD') + moment(data.endTime).format(' HH:mm:ss')).valueOf()){
} else if (
data.whetherSetApply === 'YES' &&
data.endTimeApply > moment(moment(data.calendarTime[0]).format('YYYY-MM-DD') + moment(data.endTime).format(' HH:mm:ss')).valueOf()
) {
message.warning('报名结束时间需小于上课开始时间');
resolve(false);
} else if(data.whetherSetSignIn === 'YES' && !data.signInTimeNum){
} else if (data.whetherSetSignIn === 'YES' && !data.signInTimeNum) {
message.warning('请输入签到时间');
resolve(false);
} else if(data.whetherSetSignOut === 'YES' && ((data.signOutType === 'START_LATER' && !data.signOutStartTimeNum) || !data.signOutEndTimeNum)){
} else if (data.whetherSetSignOut === 'YES' && ((data.signOutType === 'START_LATER' && !data.signOutStartTimeNum) || !data.signOutEndTimeNum)) {
message.warning('请输入签退时间');
resolve(false);
} else if (data.isMore) {
......@@ -579,7 +565,7 @@ class AddOfflineCourse extends React.Component {
resolve(true);
}
});
}
};
// 使用默认封面图
handleResetCoverUrl = () => {
......@@ -589,41 +575,46 @@ class AddOfflineCourse extends React.Component {
if (isDefaultCover) return;
message.success('已替换为默认图');
this.setState({ coverUrl: defaultCoverUrl });
}
};
// 滑动加载更多讲师列表
handleScrollTeacherList = (e) => {
const { hasNext } = this.state;
const container = e.target;
const { hasNext } = this.state;
const container = e.target;
//判定元素是否滚动到底部
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && hasNext) {
const { teacherQuery } = this.state;
let _teacherQuery = teacherQuery;
_teacherQuery.current = _teacherQuery.current + 1
this.setState({
teacherQuery:{..._teacherQuery}
},()=>{this.getTeacherList(_teacherQuery.current)})
}
}
getTeacherList(current = 1, selectList){
const { teacherQuery,teacherList} = this.state;
//判定元素是否滚动到底部
const scrollToBottom = container && container.scrollHeight <= container.clientHeight + container.scrollTop;
if (scrollToBottom && hasNext) {
const { teacherQuery } = this.state;
let _teacherQuery = teacherQuery;
_teacherQuery.current = _teacherQuery.current + 1;
this.setState(
{
teacherQuery: { ..._teacherQuery },
},
() => {
this.getTeacherList(_teacherQuery.current);
}
);
}
};
getTeacherList(current = 1, selectList) {
const { teacherQuery, teacherList } = this.state;
const _query = {
...teacherQuery,
current,
size:15
size: 15,
};
StoreService.getStoreUserBasicPage( _query).then((res) => {
const { result = {} } = res;
const { records = [], total = 0, hasNext } = result;
const list = current > 1 ? teacherList.concat(records) : records;
this.setState({
hasNext,
teacherList: list,
teacherQuery:{..._query}
})
StoreService.getStoreUserBasicPage(_query).then((res) => {
const { result = {} } = res;
const { records = [], hasNext } = result;
const list = current > 1 ? teacherList.concat(records) : records;
this.setState({
hasNext,
teacherList: list,
teacherQuery: { ..._query },
});
});
}
......@@ -633,14 +624,14 @@ class AddOfflineCourse extends React.Component {
message.warning('内容过长,不能超过1000字');
}
this.setState({ introduce: value, isMore });
}
};
selectMultiDate = (calendarTime) => {
const dateList = _.sortBy(calendarTime);
this.setState({
calendarTime: dateList,
})
}
});
};
handleChangeDates = (dates) => {
const data = {};
......@@ -652,15 +643,15 @@ class AddOfflineCourse extends React.Component {
data.endTimeApply = dates[1].startOf('minute').valueOf() + 59000;
}
this.setState(data);
}
};
whetherVisitorsJoinChange = ()=>{
if(this.state.whetherVisitorsJoin === "NO"){
whetherVisitorsJoinChange = () => {
if (this.state.whetherVisitorsJoin === 'NO') {
this.setState({ whetherVisitorsJoin: 'YES' });
}else{
} else {
this.setState({ whetherVisitorsJoin: 'NO' });
}
}
};
handleChangeCatalogList = (value, label) => {
this.setState({ categoryId: value, categoryName: label[0] });
......@@ -674,14 +665,11 @@ class AddOfflineCourse extends React.Component {
coverUrl,
introduce,
categoryId,
categoryList,
courseCatalogList,
whetherVisitorsJoin,
loadintroduce,
showSelectCoverModal,
visible,
hasImgReady,
cutImageBlob,
teacherId,
teacherList,
calendarTime,
......@@ -709,64 +697,66 @@ class AddOfflineCourse extends React.Component {
} = this.state;
const isDefaultCover = coverUrl === defaultCoverUrl;
return (
<div className="page add-offline-course-page">
<Breadcrumbs
navList={pageType === "add" ? "新建线下课" : "编辑线下课"}
goBack={this.handleGoBack}
/>
<div className='page add-offline-course-page'>
<Breadcrumbs navList={pageType === 'add' ? '新建线下课' : '编辑线下课'} goBack={this.handleGoBack} />
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
<div className='box'>
<div className='show-tips'>
<ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
</div>
<div className="form">
<div className="basic-info__wrap">
<div className="title">基本信息</div>
<div className="course-name">
<span className="label"><span className="require">*</span>课程名称:</span>
<div className='form'>
<div className='basic-info__wrap'>
<div className='title'>基本信息</div>
<div className='course-name'>
<span className='label'>
<span className='require'>*</span>课程名称:
</span>
<Input
value={courseName}
placeholder="请输入线下课的名称(40字以内)"
placeholder='请输入线下课的名称(40字以内)'
maxLength={40}
style={{ width: 240 }}
onChange={(e) => { this.setState({ courseName: e.target.value }) }}
onChange={(e) => {
this.setState({ courseName: e.target.value });
}}
/>
</div>
<div className="course-cover">
<span className="label">封面图:</span>
<div className='course-cover'>
<span className='label'>封面图:</span>
<div className="course-cover__wrap">
<div className="img-content">
{
isDefaultCover && <span className="tag">默认图</span>
}
<img src={coverUrl} />
<div className='course-cover__wrap'>
<div className='img-content'>
{isDefaultCover && <span className='tag'>默认图</span>}
<img src={coverUrl} alt='' />
</div>
<div className="opt-btns">
<Button onClick={() => {
this.setState({
showSelectCoverModal: true
})
}}>上传图片</Button>
<span
className={`default-btn ${isDefaultCover ? 'disabled' : ''}`}
onClick={this.handleResetCoverUrl}
>使用默认图</span>
<div className="tips">建议尺寸1280*720px,图片支持jpg、jpeg、png格式。</div>
<div className='opt-btns'>
<Button
onClick={() => {
this.setState({
showSelectCoverModal: true,
});
}}>
上传图片
</Button>
<span className={`default-btn ${isDefaultCover ? 'disabled' : ''}`} onClick={this.handleResetCoverUrl}>
使用默认图
</span>
<div className='tips'>建议尺寸1280*720px,图片支持jpg、jpeg、png格式。</div>
</div>
</div>
</div>
<div className="course-catalog">
<span className="label special"><span className="require">*</span>课程分类:</span>
<div className='course-catalog'>
<span className='label special'>
<span className='require'>*</span>课程分类:
</span>
<TreeSelect
showSearch
treeNodeFilterProp="title"
treeNodeFilterProp='title'
style={{ width: 240 }}
dropdownStyle={{ maxHeight: 300, overflow: "auto" }}
dropdownStyle={{ maxHeight: 300, overflow: 'auto' }}
treeData={courseCatalogList}
placeholder="请选择课程类型"
placeholder='请选择课程类型'
allowClear
value={categoryId}
treeDefaultExpandAll
......@@ -775,184 +765,189 @@ class AddOfflineCourse extends React.Component {
}}
/>
</div>
<div className="course-catalog">
<span className="label special"><span className="require">*</span>上课地点:</span>
<div className='course-catalog'>
<span className='label special'>
<span className='require'>*</span>上课地点:
</span>
<Input
value={offlinePlace}
maxLength={40}
style={{ width: 240 }}
placeholder="请输入上课地点(40字以内)"
placeholder='请输入上课地点(40字以内)'
onChange={(e) => {
this.setState({ offlinePlace: e.target.value })
this.setState({ offlinePlace: e.target.value });
}}
/>
</div>
<div className="course-catalog" id="teacher">
<span className="label special"><span className="require">* </span>讲师:</span>
<div className='course-catalog' id='teacher'>
<span className='label special'>
<span className='require'>* </span>讲师:
</span>
<Select
placeholder="请选择讲师"
placeholder='请选择讲师'
value={teacherId}
style={{ width: 240 }}
showSearch
allowClear
filterOption={(input, option) => option}
dropdownClassName="offline-dropdown-box"
dropdownClassName='offline-dropdown-box'
onPopupScroll={this.handleScrollTeacherList}
suffixIcon={<span className="icon iconfont" style={{fontSize:'12px',color:'#BFBFBF'}}>&#xe835;</span>}
suffixIcon={
<span className='icon iconfont' style={{ fontSize: '12px', color: '#BFBFBF' }}>
&#xe835;
</span>
}
onChange={(value, option) => {
if (option) {
this.setState({ teacherId: value, teacherName: option.children });
}else{
this.setState({ teacherId: value, teacherName: "" });
} else {
this.setState({ teacherId: value, teacherName: '' });
}
}}
onSearch={(value) => {
let _teacherQuery = {...this.state.teacherQuery};
_teacherQuery.nickName = value
this.setState({
teacherQuery: _teacherQuery
}, () => {
this.getTeacherList()
})
let _teacherQuery = { ...this.state.teacherQuery };
_teacherQuery.nickName = value;
this.setState(
{
teacherQuery: _teacherQuery,
},
() => {
this.getTeacherList();
}
);
}}
onClear ={(value)=>{
this.setState({
teacherQuery:{
size: 15,
current: 1,
nickName:null
onClear={(value) => {
this.setState(
{
teacherQuery: {
size: 15,
current: 1,
nickName: null,
},
},
() => {
this.getTeacherList();
}
}, () => {
this.getTeacherList()
})
}
}
getPopupContainer={() =>
document.getElementById("teacher")
}
>
{_.map(teacherList, (item, index) => {
);
}}
getPopupContainer={() => document.getElementById('teacher')}>
{_.map(teacherList, (item) => {
return (
<Option value={item.id} key={item.id}>{item.nickName}</Option>
<Option value={item.id} key={item.id}>
{item.nickName}
</Option>
);
})}
</Select>
</div>
<div className="allow-tourist-join">
<span className="label">观看设置:</span>
<div className="content">
<div className='allow-tourist-join'>
<span className='label'>观看设置:</span>
<div className='content'>
<div>
<Switch
checked={whetherVisitorsJoin === "YES" ? true : false}
onChange={this.whetherVisitorsJoinChange}
/>
</div>
<Switch checked={whetherVisitorsJoin === 'YES' ? true : false} onChange={this.whetherVisitorsJoinChange} />
</div>
<div>
<div className="desc">
<div className='desc'>
<div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看线下课</div>
</div>
</div>
</div>
</div>
</div>
<div className="introduce">
<span className="label">课程简介:</span>
<div className="content">
<div className="intro-list">
<div className="intro-list__item introduce-editor">
{(!courseId || loadintroduce) &&
<div className='introduce'>
<span className='label'>课程简介:</span>
<div className='content'>
<div className='intro-list'>
<div className='intro-list__item introduce-editor'>
{(!courseId || loadintroduce) && (
<GraphicsEditor
id="intro"
id='intro'
isIntro={true}
maxLimit={1000}
detail={{
content: introduce
content: introduce,
}}
onChange={(val, textLength) => {
this.changeIntro(val, textLength)
this.changeIntro(val, textLength);
}}
/>
}
)}
</div>
</div>
</div>
</div>
<div className="title" style={{ marginTop: 24 }}>课程设置</div>
<div className="day">
<span className="label">
<span className="require">*</span>
上课日期:
</span>
<div className='title' style={{ marginTop: 24 }}>
课程设置
</div>
<div className='day'>
<span className='label'>
<span className='require'>*</span>
上课日期:
</span>
<div>
<div className='select-day'>
已选 <span className="mark-day">{isLongArr(calendarTime) ? calendarTime.length : 0}</span>
已选 <span className='mark-day'>{window.isLongArr(calendarTime) ? calendarTime.length : 0}</span>
</div>
<MultipleDatePicker
disabled={isEditDisablie}
selectDateList={calendarTime}
onSelect={this.selectMultiDate}
canSelectTodayBefore={false}
/>
<MultipleDatePicker disabled={isEditDisablie} selectDateList={calendarTime} onSelect={this.selectMultiDate} canSelectTodayBefore={false} />
</div>
</div>
<div className="hour" id="hour">
<span className="label"><span className="require">*</span>上课时间:</span>
<div className='hour' id='hour'>
<span className='label'>
<span className='require'>*</span>上课时间:
</span>
<TimePicker
disabled={isEditDisablie}
className="time-picker"
format="HH:mm"
className='time-picker'
format='HH:mm'
value={startTime ? moment(startTime) : null}
placeholder="开始时间"
placeholder='开始时间'
showNow={false}
style={{ width: 100, minWidth: 100}}
style={{ width: 100, minWidth: 100 }}
onSelect={(time) => {
this.setState({ startTime: time });
}}
getPopupContainer={() =>
document.getElementById("hour")
}
/>&nbsp;&nbsp;~&nbsp;&nbsp;
getPopupContainer={() => document.getElementById('hour')}
/>
&nbsp;&nbsp;~&nbsp;&nbsp;
<TimePicker
disabled={isEditDisablie}
className="time-picker"
format="HH:mm"
className='time-picker'
format='HH:mm'
value={endTime ? moment(endTime) : null}
placeholder="结束时间"
placeholder='结束时间'
showNow={false}
style={{ width: 100, minWidth: 100 }}
onSelect={(time) => {
this.setState({ endTime: time });
}}
getPopupContainer={() =>
document.getElementById("hour")
}
getPopupContainer={() => document.getElementById('hour')}
/>
</div>
<div className="course-catalog">
<span className="label"><span className="require">* </span>学员上课方式:</span>
<div className='course-catalog'>
<span className='label'>
<span className='require'>* </span>学员上课方式:
</span>
<Radio.Group
style={{ display: 'inline-block' }}
value={offlineCourseType}
onChange={(e) => {
this.setState({ offlineCourseType: e.target.value });
}}
className="mt5"
disabled={isEditDisablie}
>
<Radio value="ALL_DAY_OFFLINE" className="mr-16">
<span style={{ color: "#333" }}>所选日期都要上课</span>
className='mt5'
disabled={isEditDisablie}>
<Radio value='ALL_DAY_OFFLINE' className='mr-16'>
<span style={{ color: '#333' }}>所选日期都要上课</span>
</Radio>
<Radio value="ANY_DAY_POFFLINE" className="mr-16">
<span style={{ color: "#333" }}>选择任意1天上课</span>
<Radio value='ANY_DAY_POFFLINE' className='mr-16'>
<span style={{ color: '#333' }}>选择任意1天上课</span>
</Radio>
</Radio.Group>
</div>
<div className="course-catalog">
<span className="label">课程报名:</span>
<div className="switch-box">
<div className="switch-item" key="1">
<div className='course-catalog'>
<span className='label'>课程报名:</span>
<div className='switch-box'>
<div className='switch-item' key='1'>
<Switch
disabled={isEditDisablie}
checked={whetherSetApply === 'YES'}
......@@ -965,79 +960,118 @@ class AddOfflineCourse extends React.Component {
});
}}
/>
<span className="switch-tip">开启后可设置课程报名时间,获取报名数据</span>
<span className='switch-tip'>开启后可设置课程报名时间,获取报名数据</span>
</div>
{whetherSetApply === 'YES' && <div className="switch-item" key="2">
<span className="switch-label">报名日期:</span>
<RangePicker
id="course_date_picker"
showTime={{ showTime: 'HH:mm' }}
allowClear={false}
value={startTimeApply ? [moment(startTimeApply), moment(endTimeApply)] : null }
format={"YYYY-MM-DD HH:mm"}
onChange={(dates) => { this.handleChangeDates(dates) }}
renderExtraFooter={() => calendarTime[0] ? <div style={{ position: 'absolute', bottom: 8, cursor: 'pointer' }}>
<span
onClick={() => this.setState({ startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).subtract(1, 'days').valueOf(), endTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000 })}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}
>上课前1天</span>
<span
onClick={() => this.setState({ startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).subtract(2, 'days').valueOf(), endTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000 })}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}
>上课前2天</span>
<span
onClick={() => this.setState({ startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).subtract(3, 'days').valueOf(), endTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000 })}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}
>上课前3天</span>
</div> : null}
/>
</div>}
{whetherSetApply === 'YES' && <div className="switch-item" key="3">
<span className="switch-label">
报名人数
<Tooltip title="报名一旦开始,报名人数不支持减少">
<span style={{ margin: '0 4px', color: '#999' }} className="icon iconfont">&#xe7c4;</span>
</Tooltip>
:最多
</span>
<InputNumber
value={quota}
min={oldQuta || 1}
max={100000}
precision={0}
style={{ margin: '0 4px', width: 90 }}
disabled={oldQuta < 0}
onChange={(value) => {
this.setState({ quota: value })
}}
/>
<span className="switch-label"></span>
<span className="switch-tip">未填写时默认为不限制</span>
</div>}
{whetherSetApply === 'YES' && (
<div className='switch-item' key='2'>
<span className='switch-label'>报名日期:</span>
<RangePicker
id='course_date_picker'
showTime={{ showTime: 'HH:mm' }}
allowClear={false}
value={startTimeApply ? [moment(startTimeApply), moment(endTimeApply)] : null}
format={'YYYY-MM-DD HH:mm'}
onChange={(dates) => {
this.handleChangeDates(dates);
}}
renderExtraFooter={() => (
<If condition={calendarTime[0]}>
<div style={{ position: 'absolute', bottom: 8, cursor: 'pointer' }}>
<span
onClick={() =>
this.setState({
startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`)
.subtract(1, 'days')
.valueOf(),
endTimeApply:
moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000,
})
}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}>
上课前1天
</span>
<span
onClick={() =>
this.setState({
startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`)
.subtract(2, 'days')
.valueOf(),
endTimeApply:
moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000,
})
}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}>
上课前2天
</span>
<span
onClick={() =>
this.setState({
startTimeApply: moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`)
.subtract(3, 'days')
.valueOf(),
endTimeApply:
moment(`${moment(calendarTime[0]).format('YYYY-MM-DD')} ${moment(startTime).format('HH:mm')}`).valueOf() - 1000,
})
}
style={{
color: '#2966FF',
border: '1px solid #2966FF',
padding: '2px 8px',
borderRadius: '2px',
marginRight: 8,
}}>
上课前3天
</span>
</div>
</If>
)}
/>
</div>
)}
{whetherSetApply === 'YES' && (
<div className='switch-item' key='3'>
<span className='switch-label'>
报名人数
<Tooltip title='报名一旦开始,报名人数不支持减少'>
<span style={{ margin: '0 4px', color: '#999' }} className='icon iconfont'>
&#xe7c4;
</span>
</Tooltip>
:最多
</span>
<InputNumber
value={quota}
min={oldQuta || 1}
max={100000}
precision={0}
style={{ margin: '0 4px', width: 90 }}
disabled={oldQuta < 0}
onChange={(value) => {
this.setState({ quota: value });
}}
/>
<span className='switch-label'></span>
<span className='switch-tip'>未填写时默认为不限制</span>
</div>
)}
</div>
</div>
<div className="course-catalog">
<span className="label">考勤签到:</span>
<div className="switch-box">
<div className="switch-item" key="1">
<div className='course-catalog'>
<span className='label'>考勤签到:</span>
<div className='switch-box'>
<div className='switch-item' key='1'>
<Switch
checked={whetherSetSignIn === 'YES'}
onChange={(value) => {
......@@ -1046,64 +1080,68 @@ class AddOfflineCourse extends React.Component {
signInType: 'START_AGO',
signInTimeNum: null,
signInTimeUnit: 'MINUTE',
})
});
}}
/>
<span className="switch-tip">开启后可设置获取签到考勤数据</span>
<span className='switch-tip'>开启后可设置获取签到考勤数据</span>
</div>
{whetherSetSignIn === 'YES' && <div className="switch-item" key="2">
<span className="switch-label">签到时间:</span>
<Radio.Group
style={{ display: 'inline-block' }}
value={signInType}
onChange={(e) => {
this.setState({ signInType: e.target.value });
}}
className="mt5"
>
<Radio value="START_AGO" className="mr-16">
<span style={{ color: "#333" }}>课程开始前</span>
</Radio>
<Radio value="END_AGO" className="mr-16">
<span style={{ color: "#333" }}>课程结束前</span>
</Radio>
</Radio.Group>
</div>}
{whetherSetSignIn === 'YES' && <div className="switch-item" key="3">
<span className="switch-label">课程{signInType === 'START_AGO' ? '开始' : '结束'}</span>
<InputNumber
value={signInTimeNum}
min={1}
max={signInTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signInTimeNum: value })
}}
/>
<Select
style={{ width: 72, marginRight: 4 }}
value={signInTimeUnit}
onChange={(value) => {
const data = { signInTimeUnit: value }
if (value === 'HOUR' && signInTimeNum > 24) {
data.signInTimeNum = 24;
}
this.setState(data);
}}
>
{unitList.map(item => (
<Option value={item.key} key={item.key}>{item.value}</Option>
))}
</Select>
<span className="switch-label">内可签到</span>
</div>}
{whetherSetSignIn === 'YES' && (
<div className='switch-item' key='2'>
<span className='switch-label'>签到时间:</span>
<Radio.Group
style={{ display: 'inline-block' }}
value={signInType}
onChange={(e) => {
this.setState({ signInType: e.target.value });
}}
className='mt5'>
<Radio value='START_AGO' className='mr-16'>
<span style={{ color: '#333' }}>课程开始前</span>
</Radio>
<Radio value='END_AGO' className='mr-16'>
<span style={{ color: '#333' }}>课程结束前</span>
</Radio>
</Radio.Group>
</div>
)}
{whetherSetSignIn === 'YES' && (
<div className='switch-item' key='3'>
<span className='switch-label'>课程{signInType === 'START_AGO' ? '开始' : '结束'}</span>
<InputNumber
value={signInTimeNum}
min={1}
max={signInTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signInTimeNum: value });
}}
/>
<Select
style={{ width: 72, marginRight: 4 }}
value={signInTimeUnit}
onChange={(value) => {
const data = { signInTimeUnit: value };
if (value === 'HOUR' && signInTimeNum > 24) {
data.signInTimeNum = 24;
}
this.setState(data);
}}>
{unitList.map((item) => (
<Option value={item.key} key={item.key}>
{item.value}
</Option>
))}
</Select>
<span className='switch-label'>内可签到</span>
</div>
)}
</div>
</div>
<div className="course-catalog">
<span className="label">考勤签退:</span>
<div className="switch-box">
<div className="switch-item" key="1">
<div className='course-catalog'>
<span className='label'>考勤签退:</span>
<div className='switch-box'>
<div className='switch-item' key='1'>
<Switch
checked={whetherSetSignOut === 'YES'}
onChange={(value) => {
......@@ -1114,119 +1152,135 @@ class AddOfflineCourse extends React.Component {
signOutStartTimeUnit: 'MINUTE',
signOutEndTimeNum: null,
signOutEndTimeUnit: 'MINUTE',
})
});
}}
/>
<span className="switch-tip">开启后可设置获取签退考勤数据</span>
<span className='switch-tip'>开启后可设置获取签退考勤数据</span>
</div>
{whetherSetSignOut === 'YES' && <div className="switch-item" key="2">
<span className="switch-label">签退时间:</span>
<Radio.Group
style={{ display: 'inline-block' }}
value={signOutType}
onChange={(e) => {
this.setState({ signOutType: e.target.value });
}}
className="mt5"
>
<Radio value="START_LATER" className="mr-16">
<span style={{ color: "#333" }}>课程开始后</span>
</Radio>
<Radio value="END_LATER" className="mr-16">
<span style={{ color: "#333" }}>课程结束后</span>
</Radio>
</Radio.Group>
</div>}
{whetherSetSignOut === 'YES' && <div className="switch-item" key="3">
<span className="switch-label">课程{signOutType === 'START_LATER' ? '开始' : '结束'}</span>
{signOutType === 'START_LATER' && <InputNumber
value={signOutStartTimeNum}
min={1}
max={signOutStartTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signOutStartTimeNum: value })
}}
/>}
{signOutType === 'START_LATER' && <Select
style={{ width: 72, marginRight: 4 }}
value={signOutStartTimeUnit}
onChange={(value) => {
const data = { signOutStartTimeUnit: value }
if (value === 'HOUR' && signOutStartTimeNum > 24) {
data.signOutStartTimeNum = 24;
}
this.setState(data);
}}
>
{unitList.map(item => (
<Option value={item.key} key={item.key}>{item.value}</Option>
))}
</Select>}
{signOutType === 'START_LATER' && <span className="switch-label">就可签退,截止签退时间为下课后</span>}
<InputNumber
value={signOutEndTimeNum}
min={1}
max={signOutEndTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signOutEndTimeNum: value })
}}
/>
<Select
style={{ width: 72, marginRight: 4 }}
value={signOutEndTimeUnit}
onChange={(value) => {
const data = { signOutEndTimeUnit: value }
if (value === 'HOUR' && signOutEndTimeNum > 24) {
data.signOutEndTimeNum = 24;
}
this.setState(data);
}}
>
{unitList.map(item => (
<Option value={item.key} key={item.key}>{item.value}</Option>
))}
</Select>
{signOutType !== 'START_LATER' &&
<span className="switch-label">内可签退</span>
}
</div>}
{whetherSetSignOut === 'YES' && (
<div className='switch-item' key='2'>
<span className='switch-label'>签退时间:</span>
<Radio.Group
style={{ display: 'inline-block' }}
value={signOutType}
onChange={(e) => {
this.setState({ signOutType: e.target.value });
}}
className='mt5'>
<Radio value='START_LATER' className='mr-16'>
<span style={{ color: '#333' }}>课程开始后</span>
</Radio>
<Radio value='END_LATER' className='mr-16'>
<span style={{ color: '#333' }}>课程结束后</span>
</Radio>
</Radio.Group>
</div>
)}
{whetherSetSignOut === 'YES' && (
<div className='switch-item' key='3'>
<span className='switch-label'>课程{signOutType === 'START_LATER' ? '开始' : '结束'}</span>
{signOutType === 'START_LATER' && (
<InputNumber
value={signOutStartTimeNum}
min={1}
max={signOutStartTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signOutStartTimeNum: value });
}}
/>
)}
{signOutType === 'START_LATER' && (
<Select
style={{ width: 72, marginRight: 4 }}
value={signOutStartTimeUnit}
onChange={(value) => {
const data = { signOutStartTimeUnit: value };
if (value === 'HOUR' && signOutStartTimeNum > 24) {
data.signOutStartTimeNum = 24;
}
this.setState(data);
}}>
{unitList.map((item) => (
<Option value={item.key} key={item.key}>
{item.value}
</Option>
))}
</Select>
)}
{signOutType === 'START_LATER' && <span className='switch-label'>就可签退,截止签退时间为下课后</span>}
<InputNumber
value={signOutEndTimeNum}
min={1}
max={signOutEndTimeUnit === 'MINUTE' ? 1440 : 24}
precision={0}
style={{ margin: '0 4px', width: 90 }}
onChange={(value) => {
this.setState({ signOutEndTimeNum: value });
}}
/>
<Select
style={{ width: 72, marginRight: 4 }}
value={signOutEndTimeUnit}
onChange={(value) => {
const data = { signOutEndTimeUnit: value };
if (value === 'HOUR' && signOutEndTimeNum > 24) {
data.signOutEndTimeNum = 24;
}
this.setState(data);
}}>
{unitList.map((item) => (
<Option value={item.key} key={item.key}>
{item.value}
</Option>
))}
</Select>
{signOutType !== 'START_LATER' && <span className='switch-label'>内可签退</span>}
</div>
)}
</div>
</div>
</div>
</div>
</div>
<div className="footer">
<div className='footer'>
<Button onClick={this.handleGoBack}>取消</Button>
<Button onClick={this.handleShowPreviewModal}>预览</Button>
<Button type="primary" onClick={_.debounce(() => this.preSubmit(), 3000, true)}>保存</Button>
<Button type='primary' onClick={_.debounce(() => this.preSubmit(), 3000, true)}>
保存
</Button>
</div>
{showSelectCoverModal &&
{showSelectCoverModal && (
<SelectPrepareFileModal
key="basic"
operateType="select"
key='basic'
operateType='select'
multiple={false}
accept="image/jpeg,image/png,image/jpg"
accept='image/jpeg,image/png,image/jpg'
selectTypeList={['JPG', 'JPEG', 'PNG']}
tooltip='支持文件类型:jpg、jpeg、png'
isOpen={showSelectCoverModal}
onClose={() => {
this.setState({ showSelectCoverModal: false })
this.setState({ showSelectCoverModal: false });
}}
onSelect={this.handleSelectCover}
/>
}
{ visible &&
<ImgClipModal visible={visible} imgUrl={imageFile.ossUrl} onConfirm={this.getSignature} onClose={()=>{this.setState({ visible: false });}}/>
}
{ this.state.previewOfflineModal }
)}
{visible && (
<ImgClipModal
visible={visible}
imgUrl={imageFile.ossUrl}
onConfirm={this.getSignature}
onClose={() => {
this.setState({ visible: false });
}}
/>
)}
{this.state.previewOfflineModal}
</div>
)
);
}
}
......
/*
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Last Modified by: chenshu
* @Last Modified time: 2021-04-06 16:17:57
* @Description: 添加直播-简介
*/
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { Col, message, Row, Switch } from 'antd';
import React from 'react';
import { Input, message, Upload, Radio, Row, Col, Button, Popover, Switch } from 'antd';
import Service from '@/common/js/service';
import GraphicsEditor from '../../components/GraphicsEditor';
import User from '@/common/js/user';
import UploadOss from '@/core/upload';
import './AddGraphicsIntro.less';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components';
const { TextArea } = Input;
class AddGraphicsIntro extends React.Component {
constructor(props) {
super(props);
this.state = {
showSelectFileModal: false,
diskList: [],
selectType: null,
}
};
}
// 上传封面图
handleShowImgCutModal = (event) => {
const imageFile = event.target.files[0];
if (!imageFile) return;
if (!imageFile) return;
this.setState({
imageFile,
showCutModal: true,
});
}
};
// 选择暖场资源
handleSelectVideo = (file) => {
const { selectType } = this.state;
// 选择暖场资源
handleSelectVideo = (file) => {
const { selectType } = this.state;
this.setState({
showSelectFileModal: false
})
showSelectFileModal: false,
});
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){
if (selectType === 'WARMUP') {
const liveCourseWarmMedia = {
contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId,
mediaUrl: ossUrl,
mediaName: folderName,
size: folderSize
}
size: folderSize,
};
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{
} else {
// 最多添加九图片
const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE";
return item.mediaType == 'PICTURE';
});
if (list.length > 8) {
message.warning("最多添加9张图片");
message.warning('最多添加9张图片');
return;
}
liveCourseMediaRequests.push({
......@@ -78,121 +70,128 @@ class AddGraphicsIntro extends React.Component {
});
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
}
};
changeDetail = (value) => {
this.props.onChange('courseMedia', value);
}
};
changeIntro = (value) => {
this.props.onChange('introduce', value);
}
};
whetherVisitorsJoinChange = ()=>{
if(this.props.data.whetherVisitorsJoin==="NO"){
this.props.onChange('whetherVisitorsJoin','YES')
}else{
this.props.onChange('whetherVisitorsJoin','NO')
whetherVisitorsJoinChange = () => {
if (this.props.data.whetherVisitorsJoin === 'NO') {
this.props.onChange('whetherVisitorsJoin', 'YES');
} else {
this.props.onChange('whetherVisitorsJoin', 'NO');
}
}
};
shelfStateChange = ()=>{
if(this.props.data.shelfState==="NO"){
this.props.onChange('shelfState','YES')
}else{
this.props.onChange('shelfState','NO')
shelfStateChange = () => {
if (this.props.data.shelfState === 'NO') {
this.props.onChange('shelfState', 'YES');
} else {
this.props.onChange('shelfState', 'NO');
}
}
};
render() {
const {data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce } } = this.props;
const {
data: { id, whetherVisitorsJoin, courseMedia, introduce, shelfState, loadcourseMedia, loadintroduce },
} = this.props;
const { showSelectFileModal, selectType } = this.state;
return (
<div className="add-video__intro-info">
<div className="allow-tourist-join">
<span className="label">观看设置:</span>
<div className="content">
<div className='add-video__intro-info'>
<div className='allow-tourist-join'>
<span className='label'>观看设置:</span>
<div className='content'>
<div>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/>
</div>
<Switch checked={whetherVisitorsJoin === 'YES' ? true : false} onChange={this.whetherVisitorsJoinChange} />
</div>
<div>
<div className="desc">
<div className='desc'>
<div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看图文课</div>
</div>
</div>
</div>
</div>
</div>
<div className="store-show">
<span className="label">学院展示:</span>
<div className="content">
<Row>
<Col span={3}>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/>
</Col>
<Col span={21}>
<div className="desc">
<div>开启:图文课将在学员学院图文课列表中展示</div>
<div>关闭:图文课将在学员学院图文课列表中隐藏</div>
</div>
</Col>
</Row>
<div className='store-show'>
<span className='label'>学院展示:</span>
<div className='content'>
<Row>
<Col span={3}>
<Switch checked={shelfState === 'YES' ? true : false} onChange={this.shelfStateChange} />
</Col>
<Col span={21}>
<div className='desc'>
<div>开启:图文课将在学员学院图文课列表中展示</div>
<div>关闭:图文课将在学员学院图文课列表中隐藏</div>
</div>
</Col>
</Row>
</div>
</div>
<div className="introduce required">
<span className="label" style={{ marginTop: 5 }}>课程内容:</span>
<div className="content">
<div className="intro-list">
<div className="intro-list__item content-editor">
{(!id || loadcourseMedia) &&
<div className='introduce required'>
<span className='label' style={{ marginTop: 5 }}>
课程内容:
</span>
<div className='content'>
<div className='intro-list'>
<div className='intro-list__item content-editor'>
{(!id || loadcourseMedia) && (
<GraphicsEditor
id="content"
id='content'
detail={{
content: courseMedia
content: courseMedia,
}}
onChange={(val) => {
this.changeDetail(val);
}}
onChange={(val) => { this.changeDetail(val) }}
/>
}
)}
</div>
</div>
</div>
</div>
<div className="introduce">
<span className="label">课程简介:</span>
<div className="content">
<div className="intro-list">
<div className="intro-list__item introduce-editor">
{(!id || loadintroduce) &&
<div className='introduce'>
<span className='label'>课程简介:</span>
<div className='content'>
<div className='intro-list'>
<div className='intro-list__item introduce-editor'>
{(!id || loadintroduce) && (
<GraphicsEditor
id="intro"
id='intro'
isIntro={true}
detail={{
content: introduce
content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}}
onChange={(val) => { this.changeIntro(val) }}
/>
}
)}
</div>
</div>
</div>
</div>
{/* 选择暖场图文件弹窗 */}
{ showSelectFileModal &&
{showSelectFileModal && (
<SelectPrepareFileModal
operateType="select"
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] }
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'}
operateType='select'
accept={selectType === 'INTRO' ? 'image/jpeg,image/png,image/jpg' : 'video/mp4,image/jpeg,image/png,image/jpg'}
selectTypeList={selectType === 'INTRO' ? ['JPG', 'JPEG', 'PNG'] : ['MP4', 'JPG', 'JPEG', 'PNG']}
tooltip={selectType === 'INTRO' ? '支持文件类型:jpg、jpeg、png' : '支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal}
onClose={() => {
this.setState({ showSelectFileModal: false })
this.setState({ showSelectFileModal: false });
}}
onSelect={this.handleSelectVideo}
/>
}
)}
</div>
)
);
}
}
......
......@@ -17,6 +17,7 @@ import OfflineCourseData from '@/modules/course-manage/offline-course/OfflineCou
import { Dropdown, message, Modal, Switch, Tooltip } from 'antd';
import moment from 'moment';
import React from 'react';
import { find, reduce, last } from 'underscore';
import { Route, withRouter } from 'react-router-dom';
import ENUM from '../../../knowledge-base/ENUM.js';
import PreviewOfflineModal from '../modal/PreviewOfflineModal';
......@@ -44,7 +45,7 @@ class OfflineCourseList extends React.Component {
handlePlanName = (planArray) => {
let planStr = '';
planArray.map((item, index) => {
planArray.forEach((item, index) => {
if (index < planArray.length - 1) {
planStr = planStr + item.planName + '、';
} else {
......@@ -64,13 +65,13 @@ class OfflineCourseList extends React.Component {
fixed: 'left',
render: (val, record) => {
const { courseMediaVOS, courseName, offlinePlace, calendarTime, startTime, endTime } = record;
const coverUrl = (_.find(courseMediaVOS, (data) => data.contentType === 'COVER') || {}).mediaUrl;
const coverUrl = (find(courseMediaVOS, (data) => data.contentType === 'COVER') || {}).mediaUrl;
let isContinue = calendarTime.length > 1;
_.reduce(calendarTime, (a, b) => {
reduce(calendarTime, (a, b) => {
isContinue = isContinue && b - a === 86400000;
return b;
});
const lastTime = _.last(calendarTime);
const lastTime = last(calendarTime);
const time = `${
!isContinue
? calendarTime.map((item) => moment(item).format('MM-DD')).join('、')
......@@ -138,7 +139,9 @@ class OfflineCourseList extends React.Component {
width: 120,
dataIndex: 'courseware',
render: (val, item, index) => {
return <Switch disabled={item.courseState === 'EXPIRED'} checked={item.shelfState === 'YES'} onChange={() => this.changeShelfState(item)} />;
return (
<Switch size='small' disabled={item.courseState === 'EXPIRED'} checked={item.shelfState === 'YES'} onChange={() => this.changeShelfState(item)} />
);
},
},
{
......
/*
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Author: 吴文洁
* @Date: 2020-07-16 11:05:17
* @Last Modified by: chenshu
* @Last Modified time: 2021-04-06 16:44:09
* @Description: 添加直播-简介
*/
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { Col, message, Row, Switch } from 'antd';
import React from 'react';
import { Input, message, Upload, Radio, Row, Col, Button, Popover, Switch } from 'antd';
import Service from '@/common/js/service';
import GraphicsEditor from '../../components/GraphicsEditor';
import User from '@/common/js/user';
import UploadOss from '@/core/upload';
import { filter } from 'underscore';
import './AddVideoIntro.less';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import { DISK_MAP } from '@/common/constants/academic/lessonEnum';
import { ImgCutModalNew } from '@/components';
const { TextArea } = Input;
const defaultCover = 'https://xiaomai-image.oss-cn-hangzhou.aliyuncs.com/1599635741526.png';
class AddVideoIntro extends React.Component {
constructor(props) {
super(props);
this.state = {
warmUrl: defaultCover,
showSelectFileModal: false,
diskList: [],
selectType:null
}
selectType: null,
};
}
// 上传封面图
handleShowImgCutModal = (event) => {
const imageFile = event.target.files[0];
if (!imageFile) return;
if (!imageFile) return;
this.setState({
imageFile,
showCutModal: true,
});
}
};
// 选择暖场资源
handleSelectVideo = (file) => {
const { selectType } = this.state;
// 选择暖场资源
handleSelectVideo = (file) => {
const { selectType } = this.state;
this.setState({
showSelectFileModal: false
})
showSelectFileModal: false,
});
const { ossUrl, resourceId, folderName, folderFormat, folderSize } = file;
if(selectType === 'WARMUP'){
if (selectType === 'WARMUP') {
const liveCourseWarmMedia = {
contentType: 'WARMUP',
mediaType: folderFormat === 'MP4' ? 'VIDEO' : 'PICTURE',
mediaContent: resourceId,
mediaUrl: ossUrl,
mediaName: folderName,
size: folderSize
}
size: folderSize,
};
this.props.onChange('liveCourseWarmMedia', liveCourseWarmMedia);
}else{
// 最多添加九图片
const { liveCourseMediaRequests } = this.props.data;
} else {
// 最多添加九图片
const { liveCourseMediaRequests } = this.props.data;
const list = _.filter(liveCourseMediaRequests, (item) => {
return item.mediaType == "PICTURE";
});
if (list.length > 8) {
message.warning("最多添加9张图片");
return;
}
liveCourseMediaRequests.push({
contentType: 'INTRO',
size: folderSize,
mediaName: folderName,
mediaContent: resourceId,
mediaType: 'PICTURE',
mediaUrl: ossUrl,
});
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
const list = filter(liveCourseMediaRequests, (item) => {
return item.mediaType === 'PICTURE';
});
if (list.length > 8) {
message.warning('最多添加9张图片');
return;
}
liveCourseMediaRequests.push({
contentType: 'INTRO',
size: folderSize,
mediaName: folderName,
mediaContent: resourceId,
mediaType: 'PICTURE',
mediaUrl: ossUrl,
});
this.props.onChange('liveCourseMediaRequests', liveCourseMediaRequests);
}
}
};
changeIntro = (value) => {
this.props.onChange('introduce', value);
}
};
handleUpload = (Blob) => {
this.setState({
showSelectFileModal: true,
selectType:'INTRO'
})
}
whetherVisitorsJoinChange = ()=>{
if(this.props.data.whetherVisitorsJoin==="NO"){
this.props.onChange('whetherVisitorsJoin','YES')
}else{
this.props.onChange('whetherVisitorsJoin','NO')
selectType: 'INTRO',
});
};
whetherVisitorsJoinChange = () => {
if (this.props.data.whetherVisitorsJoin === 'NO') {
this.props.onChange('whetherVisitorsJoin', 'YES');
} else {
this.props.onChange('whetherVisitorsJoin', 'NO');
}
}
shelfStateChange = ()=>{
if(this.props.data.shelfState==="NO"){
this.props.onChange('shelfState','YES')
}else{
this.props.onChange('shelfState','NO')
};
shelfStateChange = () => {
if (this.props.data.shelfState === 'NO') {
this.props.onChange('shelfState', 'YES');
} else {
this.props.onChange('shelfState', 'NO');
}
}
};
render() {
const {data: { whetherVisitorsJoin,liveCourseMediaRequests = [], shelfState, id, introduce, loadintroduce } } = this.props;
const {showSelectFileModal,selectType} = this.state
const {
data: { whetherVisitorsJoin, shelfState, id, introduce, loadintroduce },
} = this.props;
const { showSelectFileModal, selectType } = this.state;
return (
<div className="add-video__intro-info">
<div className="allow-tourist-join">
<span className="label">观看设置:</span>
<div className="content">
<div className='add-video__intro-info'>
<div className='allow-tourist-join'>
<span className='label'>观看设置:</span>
<div className='content'>
<div>
<Switch checked={whetherVisitorsJoin==="YES"? true:false} onChange={this.whetherVisitorsJoinChange}/>
</div>
<Switch checked={whetherVisitorsJoin === 'YES' ? true : false} onChange={this.whetherVisitorsJoinChange} />
</div>
<div>
<div className="desc">
<div className='desc'>
<div>开启:允许未绑定手机号的学员观看</div>
<div>关闭:仅限绑定了手机号的学员可以进入观看视频</div>
</div>
</div>
</div>
</div>
</div>
<div className="store-show">
<span className="label">学院展示:</span>
<div className="content">
<Row>
<Col span={3}>
<Switch checked={shelfState==="YES"? true:false} onChange={this.shelfStateChange}/>
</Col>
<Col span={21}>
<div className="desc">
<div>开启:此视频将在学员学院的视频列表中出现</div>
<div>关闭:此视频将在学员学院的视频列表中隐藏</div>
</div>
</Col>
</Row>
<div className='store-show'>
<span className='label'>学院展示:</span>
<div className='content'>
<Row>
<Col span={3}>
<Switch checked={shelfState === 'YES' ? true : false} onChange={this.shelfStateChange} />
</Col>
<Col span={21}>
<div className='desc'>
<div>开启:此视频将在学员学院的视频列表中出现</div>
<div>关闭:此视频将在学员学院的视频列表中隐藏</div>
</div>
</Col>
</Row>
</div>
</div>
<div className="introduce">
<span className="label">视频课简介:</span>
<div className="content">
<div className="intro-list">
<div className="intro-list__item introduce-editor">
{(!id || loadintroduce) &&
<div className='introduce'>
<span className='label'>视频课简介:</span>
<div className='content'>
<div className='intro-list'>
<div className='intro-list__item introduce-editor'>
{(!id || loadintroduce) && (
<GraphicsEditor
id="intro"
id='intro'
isIntro={true}
detail={{
content: introduce
content: introduce,
}}
onChange={(val) => {
this.changeIntro(val);
}}
onChange={(val) => { this.changeIntro(val) }}
/>
}
)}
</div>
</div>
</div>
</div>
{/* 选择暖场图文件弹窗 */}
{ showSelectFileModal &&
{showSelectFileModal && (
<SelectPrepareFileModal
operateType="select"
accept={selectType==="INTRO"?"image/jpeg,image/png,image/jpg":"video/mp4,image/jpeg,image/png,image/jpg"}
selectTypeList={ selectType==="INTRO" ? ['JPG', 'JPEG', 'PNG']: ['MP4', 'JPG', 'JPEG', 'PNG'] }
tooltip={ selectType==="INTRO"?'支持文件类型:jpg、jpeg、png':'支持文件类型:jpg、jpeg、png、mp4'}
operateType='select'
accept={selectType === 'INTRO' ? 'image/jpeg,image/png,image/jpg' : 'video/mp4,image/jpeg,image/png,image/jpg'}
selectTypeList={selectType === 'INTRO' ? ['JPG', 'JPEG', 'PNG'] : ['MP4', 'JPG', 'JPEG', 'PNG']}
tooltip={selectType === 'INTRO' ? '支持文件类型:jpg、jpeg、png' : '支持文件类型:jpg、jpeg、png、mp4'}
isOpen={showSelectFileModal}
onClose={() => {
this.setState({ showSelectFileModal: false })
this.setState({ showSelectFileModal: false });
}}
onSelect={this.handleSelectVideo}
/>
}
)}
</div>
)
);
}
}
......
......@@ -159,6 +159,7 @@ class VideoCourseList extends React.Component {
render: (val, item, index) => {
return (
<Switch
size='small'
loading={ShelfLoading}
checked={item.shelfState === 'YES'}
defaultChecked={item.shelfState}
......
......@@ -7,17 +7,16 @@
* @@Copyrigh: © 2020 杭州杰竞科技有限公司 版权所有
*/
import React from 'react';
import { Button, Input, Switch, Radio, Row, Col, Modal, message, Tooltip } from 'antd';
import { Button, Input, Switch, Radio, Row, Col, message, Tooltip } from 'antd';
import { withRouter } from 'react-router-dom';
import SelectOperatorModal from '../modal/SelectOperatorModal';
import SelectPrepareFileModal from '@/modules/prepare-lesson/modal/SelectPrepareFileModal';
import Upload from '@/core/upload';
import ImgClipModal from '@/components/ImgClipModal'
import ImgClipModal from '@/components/ImgClipModal';
import './BasicInfo.less';
const { TextArea } = Input;
const defaultCover = 'https://image.xiaomaiketang.com/xm/rEAetaTEh3.png';
let cutFlag = false;
class BasicInfo extends React.Component {
constructor(props) {
super(props);
......@@ -74,7 +73,7 @@ class BasicInfo extends React.Component {
handleSelectCover = (file) => {
this.setState({
visible: true,
imageFile:file
imageFile: file,
});
};
//获取resourceId
......@@ -125,7 +124,7 @@ class BasicInfo extends React.Component {
};
render() {
const { operatorModalVisible, showSelectFileModal, visible, hasImgReady, cutImageBlob,imageFile} = this.state;
const { operatorModalVisible, showSelectFileModal, visible, imageFile } = this.state;
const { data } = this.props;
const { planName, coverUrl, instro, enableState, operateType, selectOperatorList, percentCompleteLive, percentCompleteVideo, percentCompletePicture } =
data;
......@@ -325,9 +324,16 @@ class BasicInfo extends React.Component {
onSelect={this.handleSelectCover}
/>
)}
{ visible &&
<ImgClipModal visible={visible} imgUrl={imageFile.ossUrl} onConfirm={this.getSignature} onClose={()=>{this.setState({ visible: false });}}/>
}
{visible && (
<ImgClipModal
visible={visible}
imgUrl={imageFile.ossUrl}
onConfirm={this.getSignature}
onClose={() => {
this.setState({ visible: false });
}}
/>
)}
</div>
);
}
......
......@@ -64,6 +64,7 @@ function PlanList(props) {
render: (val, item, index) => {
return (
<Switch
size='small'
checked={item.enableState === 'NO' ? false : true}
onChange={() => changeEnableState(item)}
disabled={User.getUserRole() === 'CloudManager' || User.getUserRole() === 'StoreManager' ? false : true}
......
import React, { useState, useRef, useEffect, useContext } from 'react'
import Breadcrumbs from "@/components/Breadcrumbs";
import { Form, Alert, Input, Button, InputNumber, DatePicker, Switch, Radio, message, Modal, Tooltip } from 'antd';
import { Route, withRouter } from 'react-router-dom';
import User from "@/common/js/user";
import moment from 'moment'
import Service from "@/common/js/service";
import _ from 'underscore'
import Service from '@/common/js/service';
import User from '@/common/js/user';
import Breadcrumbs from '@/components/Breadcrumbs';
import ShowTips from '@/components/ShowTips';
import { Button, DatePicker, Form, Input, InputNumber, message, Modal, Radio, Switch, Tooltip } from 'antd';
import moment from 'moment';
import React, { useEffect, useRef, useState } from 'react';
import { withRouter } from 'react-router-dom';
import GraphicsEditor from '../../course-manage/components/GraphicsEditor';
import SelectPaperModal from './SelectPaperModal'
import PreviewModal from './PreviewModal'
import ShowTips from "@/components/ShowTips";
import './AddExam.less';
import PreviewModal from './PreviewModal';
import SelectPaperModal from './SelectPaperModal';
const { RangePicker } = DatePicker;
function AddExam(props: any) {
const paperInfoInit: any = { 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 request = useRef(false);
const { match } = props;
const [examDuration, setExamDuration] = useState(undefined);
useEffect(() => {
switch (props.type) {
case "copy": // 考试列表-复制考试进入
case "edit": // 考试列表-编辑考试进入
queryExamDetail();
break;
case "organizeExam": // 试卷列表-组织考试进入
case "newPaperToAddExam": // 组卷页面-新建保存试卷并组织考试
case "editPaperToAddExam": // 组卷页面-编辑保存试卷并组织考试
setGetData(true);
setPaperInfo(props.paperInfo);
break;
}
}, [])
useEffect(() => {
setPaperId(paperInfo.paperId)
setPassRate(paperInfo.passRate)
}, [paperInfo.paperId])
useEffect(() => {
setPassScore(Math.round((paperInfo.totalScore || 0) * (passRate || 0) as any / 100))
setExamTotal(paperInfo.singleChoiceCnt + paperInfo.multiChoiceCnt + paperInfo.judgeCnt + paperInfo.gapFillingCnt + paperInfo.indefiniteChoiceCnt || 0)
}, [paperInfo.paperId, passRate])
function disabledDate(current: any) {
// Can not select days before today and today
return current && current < moment().startOf('day');
const paperInfoInit: any = { 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 request = useRef(false);
const { match } = props;
const [examDuration, setExamDuration] = useState(undefined);
useEffect(() => {
switch (props.type) {
case 'copy': // 考试列表-复制考试进入
case 'edit': // 考试列表-编辑考试进入
queryExamDetail();
break;
case 'organizeExam': // 试卷列表-组织考试进入
case 'newPaperToAddExam': // 组卷页面-新建保存试卷并组织考试
case 'editPaperToAddExam': // 组卷页面-编辑保存试卷并组织考试
setGetData(true);
setPaperInfo(props.paperInfo);
break;
}
}, [props.paperInfo, props.type, queryExamDetail]);
useEffect(() => {
setPaperId(paperInfo.paperId);
setPassRate(paperInfo.passRate);
}, [paperInfo.paperId, paperInfo.passRate]);
useEffect(() => {
setPassScore(Math.round((((paperInfo.totalScore || 0) * (passRate || 0)) as any) / 100));
setExamTotal(paperInfo.singleChoiceCnt + paperInfo.multiChoiceCnt + paperInfo.judgeCnt + paperInfo.gapFillingCnt + paperInfo.indefiniteChoiceCnt || 0);
}, [
paperInfo.gapFillingCnt,
paperInfo.indefiniteChoiceCnt,
paperInfo.judgeCnt,
paperInfo.multiChoiceCnt,
paperInfo.paperId,
paperInfo.singleChoiceCnt,
paperInfo.totalScore,
passRate,
]);
function disabledDate(current: any) {
// Can not select days before today and today
return current && current < moment().startOf('day');
}
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) as any);
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;
}
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 as any)
setAnswerAnalysis(result.answerAnalysis)
setNeedOptionDisorder(result.needOptionDisorder)
setPassScore(result.passScore)
setResultContent(result.resultContent)
setResultShow(result.resultShow)
setGetData(true)
})
if (!paperId) {
message.warning('请选择试卷');
return;
}
function handleSave() {
if (request.current) {
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;
}
setCheck(true);
const param = {
if (examStartTime + (examDuration as any) * 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: any, type: any) {
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'>&#xe6f4;</span>,
onOk: () => {
window.RCHistory.push('/examination-manage-index');
},
});
}
let title = '';
switch (props.type) {
case 'add':
case 'organizeExam':
case 'newPaperToAddExam':
case 'editPaperToAddExam':
title = '新建考试';
break;
case 'edit':
title = '编辑考试';
break;
case 'copy':
title = '复制考试';
break;
default:
break;
}
return (
<div className='page examPage'>
<Breadcrumbs navList={title} goBack={handleGoBack} />
<div className='box'>
<div className='show-tips'>
<ShowTips message='请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利' />
</div>{' '}
<div className='form'>
<div className='title'>基本信息</div>
<Form labelCol={{ span: 3 }} wrapperCol={{ span: 14 }} layout='horizontal'>
<Form.Item
label='考试名称'
validateStatus={check && (!examName ? '请输入考试名称' : examName.length > 40 && '考试名称最多40字') ? 'error' : ''}
help={check && (!examName ? '请输入考试名称' : examName.length > 40 && '考试名称最多40字')}
required>
<Input
placeholder='请输入考试名称(40字以内)'
maxLength={40}
value={examName}
onChange={(e) => {
setExamName(e.target.value);
}}
style={{ width: 320 }}
/>
</Form.Item>
<Form.Item label='选择试卷' validateStatus={check && !paperId ? 'error' : ''} help={check && !paperId && '请选择试卷'} required>
<Button
onClick={() => {
setShowModal(true);
}}>
{paperInfo.paperId ? '重新选择' : '选择试卷'}
</Button>
{paperInfo.paperId && (
<div className='paperTitle'>
<img src='https://image.xiaomaiketang.com/xm/pY5imEhjzw.png' alt='' /> {paperInfo.paperName}
</div>
)}
{paperInfo.paperId && (
<div className='table'>
<div className='header'>
<div className='item'>单选题</div>
<div className='item'>多选题</div>
<div className='item'>判断题</div>
<div className='item'>填空题</div>
<div className='item long'>不定项选择题</div>
<div className='item'>合计</div>
</div>
<div className='body-list'>
<div className='item'>{paperInfo.singleChoiceCnt || 0}</div>
<div className='item'>{paperInfo.multiChoiceCnt || 0}</div>
<div className='item'>{paperInfo.judgeCnt || 0}</div>
<div className='item'>{paperInfo.gapFillingCnt || 0}</div>
<div className='item long'>{paperInfo.indefiniteChoiceCnt || 0}</div>
<div className='item'>{examTotal}</div>
</div>
<div className='body-list'>
<div className='item'>{paperInfo.singleChoiceScore || 0}</div>
<div className='item'>{paperInfo.multiChoiceScore || 0}</div>
<div className='item'>{paperInfo.judgeScore || 0}</div>
<div className='item'>{paperInfo.gapFillingScore || 0}</div>
<div className='item long'>{paperInfo.indefiniteChoiceScore || 0}</div>
<div className='item'>{paperInfo.totalScore || 0}</div>
</div>
</div>
)}
</Form.Item>
<Form.Item
label={
<div>
<span>及格线</span>
<Tooltip title='默认为选中试卷所设置的及格线,可修改'>
<span className='icon iconfont' style={{ color: '#BFBFBF', marginLeft: 4 }}>
&#xe61d;
</span>
</Tooltip>
</div>
}
style={{ marginTop: 24 }}
validateStatus={check && !passRate ? 'error' : ''}
help={check && !passRate && '请输入及格线'}
required>
<InputNumber
value={passRate}
min={0}
max={100}
onChange={(value: any) => {
setPassRate(parseInt(value));
}}
style={{ width: 100 }}
/>
<span style={{ marginLeft: 4 }}>%</span>
<span style={{ marginLeft: 16, color: '#999' }}>
{` 总分(${paperInfo.totalScore || 0})*及格线(${passRate || 0}%)=及格分数(${passScore})`}
</span>
</Form.Item>
<Form.Item
label='考试有效期'
validateStatus={check && !examStartTime ? 'error' : ''}
help={check && !examStartTime && '请选择考试起止时间'}
required>
<RangePicker
style={{ width: 320 }}
showTime={{ defaultValue: [moment().add(5, 'minutes'), moment().add(5, 'minutes')] }}
ranges={{
近七天: [moment().add(5, 'minute'), moment().add(6, 'day').endOf('day')],
1个月: [moment().add(5, 'minute'), moment().add(1, 'month').endOf('day')],
3个月: [moment().add(5, 'minute'), moment().add(3, 'month').endOf('day')],
}}
disabledDate={disabledDate}
value={[examStartTime ? moment(Number(examStartTime)) : null, examEndTime ? moment(Number(examEndTime)) : null]}
disabledTime={disabledRangeTime}
format='YYYY/MM/DD HH:mm'
onChange={(date: any) => {
setStartTime(date && date[0]?.valueOf());
setExamEndTime(date && date[1]?.valueOf());
}}
/>
</Form.Item>
<Form.Item label='考试时长' validateStatus={check && !examDuration ? 'error' : ''} help={check && !examDuration && '请输入考试时长'} required>
<InputNumber
value={examDuration}
max={1440}
min={1}
onChange={(value: any) => {
setExamDuration(parseInt(value) as any);
}}
style={{ width: 100 }}
/>
<span style={{ marginLeft: 4 }}>分钟</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个字'}>
{(getData || props.type === 'add') && (
<GraphicsEditor
maxLimit={1000}
isIntro={true}
detail={{
content: examDesc,
}}
onChange={(val: any, len: any) => {
setExamDesc(val);
setDescLen(len);
}}
/>
)}
</Form.Item>
<div className='title' style={{ marginTop: 40 }}>
考试设置
</div>
<Form.Item label='身份验证' required>
<div style={{ display: 'flex', marginLeft: 4 }}>
<Switch
style={{ position: 'relative', top: 6 }}
checked={needPhone === 'NEED_PHONE_VERIFY'}
onChange={(val) => {
setNeedPhone(val ? 'NEED_PHONE_VERIFY' : 'DO_NOT_NEED_PHONE_VERIFY');
}}></Switch>
<div style={{ position: 'relative', top: 3, left: 8, color: '#999' }}>
<p>开启:需要绑定手机号的学员才能参加考试</p>
<p>关闭:微信/企业微信登陆直接参加考试</p>
</div>
</div>
</Form.Item>
<Form.Item label='选项乱序' required>
<div style={{ display: 'flex', marginLeft: 4 }}>
<Switch
style={{ position: 'relative', top: 6 }}
checked={needOptionDisorder === 'OPTION_RANDOM'}
onChange={(val) => {
setNeedOptionDisorder(val ? 'OPTION_RANDOM' : 'OPTION_SORT');
}}></Switch>
<div style={{ position: 'relative', top: 3, left: 8, color: '#999' }}>
<p>开启:选择题的选项随机排序</p>
<p>关闭:选择题按题目原有顺序展示</p>
</div>
</div>
</Form.Item>
<Form.Item label='考试结果查看' required>
<Radio.Group
onChange={(e: any) => {
setResultShow(e.target.value);
}}
value={resultShow}>
<Radio value={'IMMEDIATELY'}>交卷后立即显示考试结果</Radio>
<Radio value={'AFTER_EXAM_END'}>到达考试截止日期才显示结果</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label=' 考试结果内容' required>
<Radio.Group
onChange={(e: any) => {
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: any) => {
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>
</div>
{showModal && (
<SelectPaperModal
onSelect={(info: any) => {
setPaperInfo(info);
}}
paperInfo={paperInfo}
close={() => {
setShowModal(false);
}}></SelectPaperModal>
)}
<div className='footer shrink-footer'>
<Button onClick={handleGoBack}>取消</Button>
<Button
onClick={() => {
setPreview(true);
}}>
预览
</Button>
<Button type='primary' onClick={handleSave}>
保存
</Button>
</div>
{preview && (
<PreviewModal
info={{
paperId,
startTime: examStartTime,
endTime: examEndTime,
......@@ -119,384 +525,17 @@ function AddExam(props: any) {
resultContent,
answerAnalysis,
resultShow,
examDuration: (examDuration || 0) * 60 * 1000,
examDuration,
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 (!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 as any) * 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: any, type: any) {
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">&#xe6f4;</span>,
onOk: () => {
window.RCHistory.push("/examination-manage-index")
}
})
}
let title = '';
switch (props.type) {
case 'add':
case "organizeExam":
case "newPaperToAddExam":
case "editPaperToAddExam":
title = '新建考试';
break;
case 'edit':
title = '编辑考试';
break;
case 'copy':
title = '复制考试';
break;
default:
break;
}
return <div className="page examPage">
<Breadcrumbs navList={title} goBack={handleGoBack} />
<div className="box">
<div className="show-tips">
<ShowTips message="请遵守国家相关规定,切勿上传低俗色情、暴力恐怖、谣言诈骗、侵权盗版等相关内容,小麦企学院保有依据国家规定及平台规则进行处理的权利" />
</div> <div className="form">
<div className="title">基本信息</div>
<Form
labelCol={{ span: 3 }}
wrapperCol={{ span: 14 }}
layout="horizontal"
>
<Form.Item label="考试名称"
validateStatus={(check && (!examName ? '请输入考试名称' : (examName.length > 40) && '考试名称最多40字')) ? 'error' : ''}
help={check && (!examName ? '请输入考试名称' : (examName.length > 40) && '考试名称最多40字')}
required>
<Input placeholder='请输入考试名称(40字以内)' maxLength={40} value={examName} onChange={(e) => {
setExamName(e.target.value)
}} style={{ width: 320 }} />
</Form.Item>
<Form.Item label="选择试卷"
validateStatus={(check && !paperId) ? 'error' : ''}
help={check && !paperId && '请选择试卷'}
required>
<Button onClick={() => { setShowModal(true) }} >{paperInfo.paperId ? '重新选择' : '选择试卷'}</Button>
{
paperInfo.paperId && <div className="paperTitle"><img src="https://image.xiaomaiketang.com/xm/pY5imEhjzw.png" alt="" /> {paperInfo.paperName}</div>
}
{
paperInfo.paperId && <div className="table">
<div className="header">
<div className="item">单选题</div>
<div className="item">多选题</div>
<div className="item">判断题</div>
<div className="item">填空题</div>
<div className="item long">不定项选择题</div>
<div className="item">合计</div>
</div>
<div className="body-list">
<div className="item">{paperInfo.singleChoiceCnt || 0}</div>
<div className="item">{paperInfo.multiChoiceCnt || 0}</div>
<div className="item">{paperInfo.judgeCnt || 0}</div>
<div className="item">{paperInfo.gapFillingCnt || 0}</div>
<div className="item long">{paperInfo.indefiniteChoiceCnt || 0}</div>
<div className="item">{examTotal}</div>
</div>
<div className="body-list">
<div className="item">{paperInfo.singleChoiceScore || 0}</div>
<div className="item">{paperInfo.multiChoiceScore || 0}</div>
<div className="item">{paperInfo.judgeScore || 0}</div>
<div className="item">{paperInfo.gapFillingScore || 0}</div>
<div className="item long">{paperInfo.indefiniteChoiceScore || 0}</div>
<div className="item">{paperInfo.totalScore || 0}</div>
</div>
</div>
}
</Form.Item>
<Form.Item
label={<div>
<span>及格线</span>
<Tooltip title="默认为选中试卷所设置的及格线,可修改">
<span className="icon iconfont" style={{ color: '#BFBFBF', marginLeft: 4 }}>&#xe61d;</span>
</Tooltip>
</div>}
style={{ marginTop: 24 }}
validateStatus={(check && !passRate) ? 'error' : ''}
help={check && !passRate && '请输入及格线'}
required
>
<InputNumber value={passRate} min={0} max={100} onChange={(value: any) => { setPassRate(parseInt(value)) }} style={{ width: 100 }} />
<span style={{ marginLeft: 4 }}>%
</span>
<span style={{ marginLeft: 16, color: "#999" }}>
{` 总分(${paperInfo.totalScore || 0})*及格线(${passRate || 0}%)=及格分数(${passScore})`}</span>
</Form.Item>
<Form.Item label="考试有效期"
validateStatus={(check && !examStartTime) ? 'error' : ''}
help={check && !examStartTime && '请选择考试起止时间'}
required>
<RangePicker
style={{ width: 320 }}
showTime={{ defaultValue: [moment().add(5, 'minutes'), moment().add(5, 'minutes')] }}
ranges={{
'近七天': [moment().add(5, 'minute'), moment().add(6, 'day').endOf('day')],
'近1个月': [moment().add(5, 'minute'), moment().add(1, 'month').endOf('day')],
'近3个月': [moment().add(5, 'minute'), moment().add(3, 'month').endOf('day')],
}}
disabledDate={disabledDate}
value={[
examStartTime ? moment(Number(examStartTime)) : null,
examEndTime ? moment(Number(examEndTime)) : null
]}
disabledTime={disabledRangeTime}
format="YYYY/MM/DD HH:mm"
onChange={(date: any) => {
setStartTime(date && date[0]?.valueOf());
setExamEndTime(date && date[1]?.valueOf());
}}
/>
</Form.Item>
<Form.Item label="考试时长"
validateStatus={(check && !examDuration) ? 'error' : ''}
help={check && !examDuration && '请输入考试时长'}
required>
<InputNumber value={examDuration} max={1440} min={1} onChange={(value: any) => { setExamDuration(parseInt(value) as any) }} style={{ width: 100 }} />
<span style={{ marginLeft: 4 }}>分钟
</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个字'}
>
{
(getData || (props.type === 'add')) && <GraphicsEditor
maxLimit={1000}
isIntro={true}
detail={{
content: examDesc
}}
onChange={(val: any, len: any) => { setExamDesc(val); setDescLen(len) }}
/>
}
</Form.Item>
<div className="title" style={{ marginTop: 40 }}>考试设置</div>
<Form.Item label="身份验证" required>
<div style={{ display: 'flex', marginLeft: 4, }}>
<Switch style={{ position: 'relative', top: 6 }}
checked={needPhone == 'NEED_PHONE_VERIFY'}
onChange={(val) => { setNeedPhone(val ? 'NEED_PHONE_VERIFY' : 'DO_NOT_NEED_PHONE_VERIFY') }}
></Switch>
<div style={{ position: 'relative', top: 3, left: 8, color: "#999" }}><p>开启:需要绑定手机号的学员才能参加考试</p>
<p>关闭:微信/企业微信登陆直接参加考试</p></div>
</div>
</Form.Item>
<Form.Item label="选项乱序" required>
<div style={{ display: 'flex', marginLeft: 4, }}>
<Switch style={{ position: 'relative', top: 6 }}
checked={needOptionDisorder == 'OPTION_RANDOM'}
onChange={(val) => { setNeedOptionDisorder(val ? 'OPTION_RANDOM' : 'OPTION_SORT') }}
></Switch>
<div style={{ position: 'relative', top: 3, left: 8, color: "#999" }}><p>开启:选择题的选项随机排序</p>
<p>关闭:选择题按题目原有顺序展示</p></div>
</div>
</Form.Item>
<Form.Item label="考试结果查看" required>
<Radio.Group onChange={(e: any) => { setResultShow(e.target.value) }} value={resultShow}>
<Radio value={'IMMEDIATELY'}>交卷后立即显示考试结果</Radio>
<Radio value={'AFTER_EXAM_END'}>到达考试截止日期才显示结果</Radio>
</Radio.Group>
</Form.Item>
<Form.Item label=" 考试结果内容" required>
<Radio.Group onChange={(e: any) => { 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: any) => { 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>
</div>
{
showModal && <SelectPaperModal onSelect={(info: any) => {
setPaperInfo(info)
}} paperInfo={paperInfo} close={() => { setShowModal(false) }}></SelectPaperModal>
}
<div className="footer shrink-footer">
<Button onClick={handleGoBack}>取消</Button>
<Button onClick={() => { setPreview(true) }}>预览</Button>
<Button type="primary" onClick={handleSave}>保存</Button>
</div>
{
preview && <PreviewModal
info={{
paperId,
startTime: examStartTime,
endTime: examEndTime,
examName,
passRate: passRate / 100,
examStartTime,
examEndTime,
examDesc,
needPhone,
needOptionDisorder,
resultContent,
answerAnalysis,
resultShow,
examDuration,
passScore,
examTotal,
totalScore: paperInfo.totalScore
}}
onClose={() => { setPreview(false) }}></PreviewModal>
}
examTotal,
totalScore: paperInfo.totalScore,
}}
onClose={() => {
setPreview(false);
}}></PreviewModal>
)}
</div>
);
}
export default withRouter(AddExam);
\ No newline at end of file
export default withRouter(AddExam);
......@@ -3,108 +3,86 @@
* @Date: 2020-04-28 18:05:30
* @LastEditors: wufan
* @LastEditTime: 2020-12-26 14:37:23
* @Description:
* @Description:
*/
import mainRoutes from './config/mainRoutes';
import redirectRoutes from './config/redirectRoutes';
import React from 'react'
import { Redirect,HashRouter as Router,Route ,Switch} from 'react-router-dom';
import React from 'react';
import { HashRouter as Router, Route, Switch } from 'react-router-dom';
import { createHashHistory } from 'history';
import App from '../modules/root/App';
import AppContext from '@/modules/root/AppContent';
import Login from '../modules/root/Login';
import CollegeManagePage from '../modules/root/CollegeManagePage';
import CreateCollege from '../modules/root/CreateCollege';
import _ from 'underscore';
import { asyncComponent } from 'react-async-component'
import SwitchRoute from '@/modules/root/SwitchRoute';
import ErrorCollege from '@/modules/root/ErrorCollege';
const history = createHashHistory();
window.RCHistory = _.extend({}, history, {
push: (obj: any) => {
history.push(obj)
},
pushState: (obj: any) => {
history.push(obj)
},
pushStateWithStatus: (obj: any) => {
history.push(obj)
},
goBack: history.goBack,
location: history.location,
replace: (obj: any) => {
history.replace(obj)
}
push: (obj: any) => {
history.push(obj);
},
pushState: (obj: any) => {
history.push(obj);
},
pushStateWithStatus: (obj: any) => {
history.push(obj);
},
goBack: history.goBack,
location: history.location,
replace: (obj: any) => {
history.replace(obj);
},
});
const cache:any = {
path: '',
component: null
}
function dynamic (component:any) {
const resolveComponent = component
return asyncComponent({
resolve: () => {
const ts = resolveComponent()
return ts
},
})
}
export const RootRouter = () => {
return (
<Router {...history}>
<Switch>
<Route key="1" exact path="/login" render={() => <Login />} />
<Route key="2" exact path="/switch-route" render={() => <SwitchRoute />} />
<Route key="3" exact path="/college-manage" render={() => <CollegeManagePage />} />
<Route key="4" exact path="/college-manage/create" render={() => <CreateCollege />} />
<Route key="6" exact path="/error-college" render={() => <ErrorCollege />} />
<Route key="5" path="/" render={() => <AppContext />} />
</Switch>
</Router>
)
}
return (
<Router {...history}>
<Switch>
<Route key='1' exact path='/login' render={() => <Login />} />
<Route key='2' exact path='/switch-route' render={() => <SwitchRoute />} />
<Route key='3' exact path='/college-manage' render={() => <CollegeManagePage />} />
<Route key='4' exact path='/college-manage/create' render={() => <CreateCollege />} />
<Route key='6' exact path='/error-college' render={() => <ErrorCollege />} />
<Route key='5' path='/' render={() => <AppContext />} />
</Switch>
</Router>
);
};
export const MainRoutes = () => {
return (
<Switch>
{
_.map(mainRoutes, ({
path,
component,
}, key) => {
return <Route
key={key}
path={path}
render={() => {
const Component = component;
return <Component />
}}
/>
})
}
</Switch>
)
}
return (
<Switch>
{_.map(mainRoutes, ({ path, component }, key) => {
return (
<Route
key={key}
path={path}
render={() => {
const Component = component;
return <Component />;
}}
/>
);
})}
</Switch>
);
};
export const RedirectRoutes = () => {
return (
<Switch>
{
_.map(redirectRoutes, ({
path,
component,
}, key) => {
return <Route
key={key}
path={path}
render={() => {
const Component = component;
return <Component />
}}
/>
})
}
</Switch>
)
}
return (
<Switch>
{_.map(redirectRoutes, ({ path, component }, key) => {
return (
<Route
key={key}
path={path}
render={() => {
const Component = component;
return <Component />;
}}
/>
);
})}
</Switch>
);
};
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