提交 1d7c0b0b authored 作者: GOD_ZYX's avatar GOD_ZYX

完成 视频加载

上级 d954e8c7
......@@ -89,11 +89,16 @@ $GLOBAL.BaseConfig = {
plugins: [
new webpack.DefinePlugin({
'webConf': JSON.stringify($GLOBAL.webConf)
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery'
})
],
externals: {
'CKEDITOR': 'window.CKEDITOR'
'CKEDITOR': 'window.CKEDITOR',
'VideoJs': 'window.swfobject'
}
}
module.exports = $GLOBAL
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
/**
* 阅读类章节
* chapter
* handleReaded
*/
import React, { Component } from 'react'
class ChapterRead extends Component {
componentDidMount() {
const {chapter} = this.props;
if (chapter && chapter.reading) {
this.props.handleReaded();
}
}
componentWillReceiveProps(nextProps) {
if (this.props.chapter && nextProps.chapter &&
this.props.chapter.id !== nextProps.chapter.id) {
nextProps.handleReaded();
}
}
render () {
const {chapter} = this.props;
const reads = chapter.reading ? [chapter.reading] : [];
return (
<div className="play-paper">
<div className="play-paper-body">
<div className="play-paper-title"><div><h3>{chapter.name}</h3></div></div>
<div className="play-paper-content">
{reads.length ?
<ul className="play-read-files">
{reads.map((o,k) => {
return <li key={k}><a href={o.reading_attachment} target="_blank">{o.reading_content}</a></li>
})}
</ul>
:
<p className="no-data">暂无阅读材料</p>
}
</div>
</div>
</div>
);
}
}
module.exports = ChapterRead;
/**
* 作业类章节
*/
import React from 'react'
import Formsy from 'formsy-react';
import FormsyComponent from '../../components/formsy/Component.jsx'
import FormItem from '../../components/formsy/FormItem.jsx'
import CoursesAction from '../../actions/CoursesAction'
import OperateAction from '../../actions/OperateAction'
import { getRequestTypes } from '../../libs/utils';
class ChapterWork extends FormsyComponent {
constructor(props) {
super(props);
this.state = { error: '' };
}
componentDidMount () {
this.courseAction = new CoursesAction();
this.operateAction = new OperateAction();
this.startTime = (new Date()).getTime();
// 加载回答
this.props.dispatch(this.courseAction.loadChapterWork(this.props.semesterId, this.props.chapter.homework.id));
}
componentWillReceiveProps (nextProps) {
let submitType = getRequestTypes(CoursesAction.SUBMIT_CHAPTER_WORK);
switch (nextProps.action.type) {
case submitType.success:
this.enableSubmitButton();
// 提交成功,重新获取答案
nextProps.dispatch(this.courseAction.loadChapterWork(this.props.semesterId, nextProps.chapter.homework.id));
nextProps.handleSubmited(nextProps.chapter.id);
break;
case submitType.failure:
this.enableSubmitButton();
nextProps.dispatch(this.operateAction.showErrorMessage(nextProps.action.error.message || '提交章节作业失败'));
break;
}
}
/**
* 提交登录
*/
onSubmit = model => {
this.loadingSubmitButton();
const {courseId, chapter, semesterId} = this.props;
const questions = chapter.homework && chapter.homework.questions || [];
let data = {
course_id: courseId,
chapter_id:chapter.id,
work_id: chapter.homework.id,
semester_id: semesterId,
work_contents: '',
duration: Math.ceil(((new Date()).getTime() - this.startTime) / 1000),
}
// 组织返回答案结构
let answers = questions.map(q => {
return {
question_id: q.id,
descreption: model['desc_' + q.id],
file_url: model['file_' + q.id]
};
});
data.work_contents = JSON.stringify(answers);
this.props.dispatch(this.courseAction.submitChapterWork(data));
}
// 表单变更时,取消掉全局错误消息
onFormChange = () => {
this._setState({ error: '' });
}
handleUploadError = msg => {
this.props.dispatch(this.operateAction.showErrorMessage(msg || '上传文件失败'));
}
render () {
const {chapter, chapter_work} = this.props;
const questions = chapter.homework && chapter.homework.questions || [];
let work = null;
let answers = {}
if (chapter_work.data && chapter_work.data.work_contents) {
work = chapter_work.data;
try {
let answerObject = JSON.parse(work.work_contents);
answerObject.forEach(a => {
answers[a.question_id] = a;
})
} catch(e) {console.log('parse work_contents to json failed.')}
}
return (
<div className="play-paper">
<div className="play-paper-body">
<div className="play-paper-title"><div><h3>{chapter.name}</h3></div></div>
<div className="play-paper-content play-chapter-work">
<Formsy.Form
onValid={this.enableSubmitButton}
onInvalid={this.disableSubmitButton}
onValidSubmit={this.onSubmit}
onChange={this.onFormChange}
>
{questions.length ?
<ul>
{questions.map((q, qi) => {
let answer = answers[q.id] || {};
return (
<li key={qi}>
<div className="work-number">{qi + 1}.</div>
<div className="work-title">
<div className="edit_html" dangerouslySetInnerHTML={{__html: q.question_content}}></div>
</div>
<FormItem
name={'desc_' + q.id}
itemType={FormItem.TEXTRICH}
value={answer.descreption || ''}
required
/>
<FormItem
name={'file_' + q.id}
fileVal="file"
value={answer.file_url || ''}
btnClassName="upbtn"
label="请上传对应的文件附件:"
itemType={FormItem.FILE}
text="上传附件"
server="/api/tenant/util/upload-file"
fileSingleSizeLimit={1024*1024*10}
accept={[{extensions: 'docx'}]}
onFileError={this.handleUploadError}
/>
<p className="help help-file">只支持docx格式的文件,文件小于10M</p>
{answer.file_url && <a style={{display: 'block', marginBottom: '20px', color: 'blue'}} href={answer.file_url} >下载附件</a> }
</li>
);
})}
</ul>
:
<p className="no-data">暂无数据</p>
}
<p className="text-danger">{this.state.error}</p>
<div className="area-btns">
<button type="submit" disabled={!this.canSubmit() || (work && work.checker_id)} className="btn btn-primary" >{this.isSubmitLoading() ? '保存中...' : (work && work.checker_id) ? '已批改' : '提交'}</button>
<span className="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
{work ?
!work.checker_id ?
<p className="help">已于 {work.created_time} 提交,等待批改中</p>
:
<div className="play-paper-check">
<h4>已获批改 <small>批改于{work.check_date}</small></h4>
<div className="play-paper-check-item"><b>评分:</b>{work.score}</div>
<div className="play-paper-check-item">
<b>评语:</b>
<div className="edit_html" dangerouslySetInnerHTML={{__html:work.check_comments}}></div>
</div>
</div>
: null
}
</div>
</Formsy.Form>
</div>
</div>
</div>
);
}
}
module.exports = ChapterWork;
/**
* 课程资料
*
* courseId
* files
*/
import React, { Component } from 'react'
class CourseInfo extends Component {
render () {
const files = this.props.files || [];
return (
<div className="play-paper">
<div className="play-paper-body">
<div className="play-paper-title"><div><h3>课程资料</h3></div></div>
<div className="play-paper-content">
{files.length ?
<ul className="play-read-files">
{files.map((f, i) => {
return <li key={i}><a href={f.file_url} target="_blank">{f.file_name}</a></li>
})}
</ul>
:
<p className="no-data">暂无课程资料</p>
}
</div>
</div>
</div>
);
}
}
module.exports = CourseInfo;
/**
* 课程大作业
* porps:
* course
* course_work
* action
* dispatch
*/
import React, { Component } from 'react'
import { Link } from 'react-router';
import Formsy from 'formsy-react';
import FormsyComponent from '../../components/formsy/Component.jsx'
import FormItem from '../../components/formsy/FormItem.jsx'
import CoursesAction from '../../actions/CoursesAction'
import OperateAction from '../../actions/OperateAction'
import { getRequestTypes } from '../../libs/utils';
class CourseWork extends FormsyComponent {
constructor(props) {
super(props);
this.state = { error: '' };
}
componentDidMount () {
this.courseAction = new CoursesAction();
this.operateAction = new OperateAction();
this.courseId = this.props.course.course_id;
this.semesterId = this.props.semesterId;
// 加载回答
this.props.dispatch(this.courseAction.loadCourseWork(this.semesterId, this.courseId));
}
componentWillReceiveProps (nextProps) {
let submitType = getRequestTypes(CoursesAction.SUBMIT_COURSE_WORK);
switch (nextProps.action.type) {
case submitType.success:
this.enableSubmitButton();
if (nextProps.action.response.data.status == 0) {
nextProps.dispatch(this.operateAction.showErrorMessage('账号出错,请联系管理员'));
console.log(JSON.stringify(nextProps.action.response.data.error))
break;
}
// 提交成功,重新获取答案
nextProps.dispatch(this.courseAction.loadCourseWork(this.semesterId, this.courseId));
nextProps.handleSubmited('work');
break;
case submitType.failure:
this.enableSubmitButton();
nextProps.dispatch(this.operateAction.showErrorMessage(nextProps.action.error.message || '提交课程大作业失败'));
break;
}
}
/**
* 提交
*/
onSubmit = model => {
this.loadingSubmitButton();
model.course_id = this.props.course.course_id;
model.semester_id = this.props.semesterId;
this.props.dispatch(this.courseAction.submitCourseWork(model));
}
// 表单变更时,取消掉全局错误消息
onFormChange = () => {
this._setState({ error: '' });
}
handleUploadError = msg => {
this.props.dispatch(this.operateAction.showErrorMessage(msg || '上传文件失败'));
}
render () {
const {course, course_work} = this.props;
const info = course_work.data || {};
return (
<div className="play-paper">
<div className="play-paper-body">
<div className="play-paper-title"><div><h3>课程大作业</h3></div></div>
<div className="play-paper-content">
<div className="play-paper-step">&#9312; 阅读大作业要求</div>
<div className="edit_html" dangerouslySetInnerHTML={{__html: course.curriculum && course.curriculum.curriculum_essay || ''}}></div>
<p>截止日期:{course.essay_date || ''}</p>
<div className="play-paper-step">&#9313; 填写作业主题、摘要,上传附件(点击“提交”保存)</div>
<Formsy.Form
onValid={this.enableSubmitButton}
onInvalid={this.disableSubmitButton}
onValidSubmit={this.onSubmit}
onChange={this.onFormChange}
>
<input type="hidden" name="id" value={info.id || ''} />
<div>
<FormItem
name="essay_name"
value={info.essay_name || ''}
placeholder="主题"
required
/>
<FormItem
name="essay_description"
value={info.essay_description || ''}
label="摘要"
itemType={FormItem.TEXTRICH}
required
/>
<FormItem
name="url"
fileVal="file"
value ={info.file_url || ''}
btnClassName="upbtn"
label="大作业附件:"
itemType={FormItem.FILE}
text="选择附件"
server="/api/tenant/util/upload-file"
fileSingleSizeLimit={1024*1024*10}
accept={[{extensions: 'docx'}]}
onFileError={this.handleUploadError}
required
/>
<p className="help help-file">只支持docx格式的文件,文件小于10M</p>
{info.file_url && <a style={{display: 'block', marginBottom: '20px', color: 'blue'}} href={info.file_url} >下载附件</a> }
</div>
<p className="text-danger">{this.state.error}</p>
<div className="area-btns">
<div className="play-paper-step">&#9314; 截止日期前提交</div>
<button type="submit" disabled={!this.canSubmit() || info.checker_id} className="btn btn-primary" >{this.isSubmitLoading() ? '保存中...' : info.checker_id ? '已批改' : '提交'}</button>
<span className="help-info">&emsp;&emsp;在获老师批改之前,可以多次提交,将以最后一次提交为准</span>
{info.id ?
!info.checker_id ?
<p className="help">已于 {info.created_time} 提交,等待批改中</p>
:
<div className="play-paper-check">
<h4>已获批改 <small>批改于{info.check_date}</small></h4>
<div className="play-paper-check-item"><b>评分:</b>{info.score}</div>
<div className="play-paper-check-item">
<b>评语:</b>
<div className="edit_html" dangerouslySetInnerHTML={{__html:info.check_comments}}></div>
</div>
</div>
: null
}
</div>
</Formsy.Form>
</div>
</div>
</div>
);
}
}
module.exports = CourseWork
差异被折叠。
/**
* 侧边章节导航列表
* props:
* chapters []
* getProgressByChapterId func
* courseId
* chapterId string
* progress number
*/
import React, { Component } from 'react'
import { Link } from 'react-router';
import ProgressCircle from '../../components/ProgressCircle.jsx'
import {chapterType} from '../../libs/const'
const NAV_COURSE = {
name: '大作业及资料',
children: [{
id: 'work',
type: chapterType.WORKOREXAM,
name: '课程大作业',
homework: {work_type: chapterType.WORK_HOME}
}, {
id: 'info',
type: chapterType.READ,
name: '课程资料'
}]
};
class SideList extends Component {
reloadPages () {
window.location.reload()
}
render () {
const {chapters, getProgressByChapterId, semesterId, courseId, chapterId, progress} = this.props;
let list = (chapters || []).concat([NAV_COURSE]);
return (
<div className="tab-pane current">
<ul className="under-control chapter-list current">
{list.map((item, index) => {
return (
<li className="chapter-item" key={index}>
<span className="cpt">{item.name}</span>
<div className="knob-list-wrap">
<ul className="knob-list">
{(item.children || []).map((o, i) => {
let isCur = chapterId === o.id;
let prog = isCur ? progress : getProgressByChapterId(o.id);
let part = Math.max(Math.round(prog / 25), 0);
let type;
switch (o.type) {
case chapterType.VIDEO:
type = 'video'; break;
case chapterType.READ:
type = 'read'; break;
default:
type = 'exam';
if (o.homework && o.homework.work_type === chapterType.WORK_HOME) {
type = 'work';
}
}
return (
<li className={`knob-item ${isCur ? 'current' : ''} ${part ? ['one', 'two', 'three', 'four'][part - 1] + '-four' : ''}`} key={i}>
<ProgressCircle percent={prog} className="play-chapter-progress"/>
<i className="icon icon-pro" title={`学习进度 ${prog}%`}></i>
{(type == 'work') ?
<Link to={`/courses/${semesterId}/${courseId}/chapters/${o.id}`} className="knob-name" onClick={this.reloadPages}>{o.name}</Link>
:
<Link to={`/courses/${semesterId}/${courseId}/chapters/${o.id}`} className="knob-name" onClick={this.props.handleClickItem}>{o.name}</Link>
}
<i className={`icon-play-chapter icon-play-${type}`}></i>
</li>
);
})}
</ul>
</div>
</li>
);
})}
</ul>
</div>
);
}
}
module.exports = SideList;
/**
* 侧边显示讲义ppt
* props:
* ppts: []
* handleClickPpt: func
*/
import React, { Component } from 'react'
class SidePpt extends Component {
constructor (props) {
super(props)
this.state = { index: 0 }
}
// 根据播放时间同步展示ppt
// @param time 播放时间
setIndexByPoint = time => {
const ppts = this.props.ppts || []
const len = ppts.length
let i = 0;
for(; i < len; i++) {
if (time < ppts[i].ppt_point) {
break;
}
}
if (this.state.index !== i - 1) {
this.setState({ index: i - 1 });
}
}
//handleSyncVideoTime = e => { // 点击ppt跳转对应的播放时间
// 点击某个ppt
onClickPpt = e => {
let toIndex = e.currentTarget.getAttribute('data-index') - 0
if (this.state.index === toIndex) { return }
this.setState({ index: toIndex })
this.props.handleClickPpt(toIndex)
}
render () {
const {ppts} = this.props
return (
<div className="tab-pane current">
<div className="jiangyi-list">
<div className="jy-list">
{(ppts || []).length ?
ppts.map((item, index) => {
return (
<div key={index} onClick={this.onClickPpt} data-index={index} className={index === this.state.index ? 'current' : ''}>
<img src={item.ppt_url} alt=""/>
</div>
);
})
:
<div className="no-data">暂无讲义</div>
}
</div>
</div>
</div>
);
}
}
module.exports = SidePpt;
差异被折叠。
<template>
<div class="play-ppt" ref="wrap">
<div class="play-preview" ref="preview">
<img :src="ppts[state.index].ppt_url" class="play-ppt-img" style='vertical-align: middle' />
</div>
<div class="play-controls cl">
<div style="float: left;">
<template v-if="state.index >= 0">
<a href="#" @click="prev" style='margin: 0 20px 0 0; color: #fff;'><i class="el-icon-arrow-left"></i></a>
</template>
<template v-if="state.index + 1 < ppts.length">
<a href="#" @click="next"><i class="el-icon-arrow-right" style="color: #fff;"></i></a>
</template>
</div>
<div class="play-page">
<span class="play-now">{{state.index + 1}}</span>
/
<span class="play-total">{{ppts.length}}</span>
</div>
<div class="play-amazing">
<i :class="['el-icon-self-xuexiao', (state.sync ? 'active' : '')]" @click="onToggleSync"></i>
<i class="el-icon-self-quanping" @click="() => { this.$emit('onPptOnly') }"></i>
<i class="el-icon-self-shipin" @click="onSetVideoTime"></i>
<i class="el-icon-self-guanbi" @click="() => { this.$emit('onClose') }"></i>
</div>
</div>
</div>
</template>
<script>
/**
* ppt播放框
* 如果同步显示,则同步props.currentIndex到state.index,否则,仅使用state.index
*/
export default {
props: {
ppts: { type: Array, require: false },
currentIndex: { type: Number, require: false, default: 0 }
},
data () {
return {
state: {
index: this.currentIndex, // ppt展示序号
sync: true // 视频播放时,同步调整ppt展示
}
}
},
watch: {
currentIndex: {
handler () {
if (this.state.sync) {
this.state.index = this.currentIndex
}
}
}
},
methods: {
gotoIndex (index) {
this.state.index = index
},
getIndex (index) {
return Math.min(this.ppts.length - 1, Math.max(0, index))
},
prev (e) {
this.state.index = this.getIndex(this.state.index - 1)
this.state.sync = false
},
next (e) {
this.state.index = this.getIndex(this.state.index + 1)
this.state.sync = false
},
onToggleSync (e) {
this.state.sync = !this.state.sync
this.state.index = this.state.sync ? this.currentIndex : this.state.index
},
onSetVideoTime (e) {
this.$emit('onVideoSyncTime', this.ppts[this.state.index].ppt_point)
},
setSize (w, h) {
this.$refs.wrap.style.width = w + 'px'
this.$refs.wrap.style.height = h + 'px'
this.$refs.preview.style.lineHeight = (h - 44) + 'px'
}
}
}
</script>
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
差异被折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论