Commit c61460e4 by zhanghaozhe

添加formik提交错误时处理

parent a4c00237
......@@ -1524,15 +1524,15 @@
}
},
"@videojs/http-streaming": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.9.3.tgz",
"integrity": "sha512-gNdqyvhxTU67optzxiywHXi/z2+Ju0b6hNth0V7BsL7YAH+R1StIKmmp6SsfFZQfrNW5ykYFoR95M/AT5cg9Ug==",
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.3.tgz",
"integrity": "sha512-fxXtwVrQBdhOFh6GymPAPCb4utCI01Zs5fdyZgtR6FSsaz/zGmnzfNS5GvNjBi/hZviMsbNPFaOTTFMMNLNA3A==",
"requires": {
"aes-decrypter": "3.0.0",
"global": "^4.3.0",
"m3u8-parser": "4.3.0",
"mpd-parser": "0.7.0",
"mux.js": "5.1.1",
"mpd-parser": "0.8.1",
"mux.js": "5.1.3",
"url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0"
}
......@@ -5867,15 +5867,15 @@
}
},
"formik": {
"version": "1.5.7",
"resolved": "https://registry.npmjs.org/formik/-/formik-1.5.7.tgz",
"integrity": "sha512-kZo8lS4WzfC2uivnSkE9DOuX9x+jVjCtIZOlb1A4lHGeURyuLt6eDfwGJzNlcP0lXIwmpANKzegiB8j60B54TA==",
"version": "1.5.8",
"resolved": "https://registry.npmjs.org/formik/-/formik-1.5.8.tgz",
"integrity": "sha512-fNvPe+ddbh+7xiByT25vuso2p2hseG/Yvuj211fV1DbCjljUEG9OpgRpcb7g7O3kxHX/q31cbZDzMxJXPWSNwA==",
"requires": {
"create-react-context": "^0.2.2",
"deepmerge": "^2.1.1",
"hoist-non-react-statics": "^3.3.0",
"lodash": "^4.17.11",
"lodash-es": "^4.17.11",
"lodash": "^4.17.14",
"lodash-es": "^4.17.14",
"prop-types": "^15.6.1",
"react-fast-compare": "^2.0.1",
"tiny-warning": "^1.0.2",
......@@ -8899,9 +8899,9 @@
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash-es": {
"version": "4.17.11",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.11.tgz",
"integrity": "sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q=="
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.15.tgz",
"integrity": "sha512-rlrc3yU3+JNOpZ9zj5pQtxnx2THmvRykwL4Xlxoa8I9lHBlVbbyPhgyPMioxVZ4NqyxaVVtaJnzsyOidQIhyyQ=="
},
"lodash._getnative": {
"version": "3.9.1",
......@@ -9515,9 +9515,9 @@
}
},
"mpd-parser": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.7.0.tgz",
"integrity": "sha512-nkzVIkecaDz3q7p4ToN3GR0FV2Odbh0w2sJ8ijsyw79JcBrJoUD3KHIiI8gL0hEDlex7mrVpTxXBsRHowUBmPw==",
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.8.1.tgz",
"integrity": "sha512-WBTJ1bKk8OLUIxBh6s1ju1e2yz/5CzhPbgi6P3F3kJHKhGy1Z+ElvEnuzEbtC/dnbRcJtMXazE3f93N5LLdp9Q==",
"requires": {
"global": "^4.3.2",
"url-toolkit": "^2.1.1"
......@@ -9548,9 +9548,9 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"mux.js": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.1.1.tgz",
"integrity": "sha512-Mf/UYmh5b8jvUP+jmrTbETnyFZprMdbT0RxKm/lJ/4d2Q3xdc5GaHaRPI1zVV5D3+6uxArVPm78QEb1RsrmaQw=="
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.1.3.tgz",
"integrity": "sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg=="
},
"nan": {
"version": "2.13.2",
......@@ -13579,13 +13579,13 @@
}
},
"string.prototype.trim": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz",
"integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.0.tgz",
"integrity": "sha512-9EIjYD/WdlvLpn987+ctkLf0FfvBefOCuiEr2henD8X+7jfwPnyvTdmW8OJhj5p+M0/96mBdynLWkxUr+rHlpg==",
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.5.0",
"function-bind": "^1.0.2"
"define-properties": "^1.1.3",
"es-abstract": "^1.13.0",
"function-bind": "^1.1.1"
}
},
"string_decoder": {
......@@ -14536,25 +14536,40 @@
}
},
"video.js": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.5.4.tgz",
"integrity": "sha512-+U3FyLVFbnJdEC6TVMv8U75c8VM00vmVY8TSfFthnvo7/6rz3LFg2Pd3TTGNbV2pEmBhkLLYO+dvmqMNUyc2ZA==",
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.0.tgz",
"integrity": "sha512-A0HSKzAmcYkd1xyExqUlM6n8bkghcX54iCvW08bPvvl3UHt8d8zijuylfIWu8vo1Z8fYyk9HPOFs1i3Cldr/cw==",
"requires": {
"@babel/runtime": "^7.2.0",
"@videojs/http-streaming": "1.9.3",
"@babel/runtime": "^7.4.5",
"@videojs/http-streaming": "1.10.3",
"global": "4.3.2",
"keycode": "^2.2.0",
"safe-json-parse": "4.0.0",
"tsml": "1.0.1",
"videojs-font": "3.1.0",
"videojs-vtt.js": "0.14.1",
"videojs-font": "3.2.0",
"videojs-vtt.js": "^0.14.1",
"xhr": "2.4.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz",
"integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
},
"regenerator-runtime": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
}
}
},
"videojs-font": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.1.0.tgz",
"integrity": "sha512-rxB68SVgbHD+kSwoNWNCHicKJuR2ga3bGfvGxmB+8fupsiLbnyCwTBVtrZUq4bZnD64mrKP1DxHiutxwrs59pQ=="
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz",
"integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA=="
},
"videojs-vtt.js": {
"version": "0.14.1",
......
......@@ -31,7 +31,7 @@
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-react": "7.12.4",
"file-loader": "2.0.0",
"formik": "^1.5.7",
"formik": "^1.5.8",
"fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-alpha.2",
"http-proxy-middleware": "^0.19.1",
......@@ -74,7 +74,7 @@
"style-loader": "0.23.1",
"terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2",
"video.js": "^7.5.4",
"video.js": "^7.6.0",
"webpack": "4.28.3",
"webpack-dev-server": "3.1.14",
"webpack-manifest-plugin": "2.0.4",
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -416,6 +416,12 @@ Created by iconfont
<glyph glyph-name="gouwuche-xianxing" unicode="&#59003;" d="M440-20m-44 0a44 44 0 1 1 88 0 44 44 0 1 1-88 0ZM850-20m-44 0a44 44 0 1 1 88 0 44 44 0 1 1-88 0ZM937.9 119.5H362.1c-3.1 0-8.5 4.5-9.2 10.5L297 548.1 265.6 729c-7.1 57.7-57.9 103-115.8 103H86.1C73.9 832 64 822.1 64 809.9c0-12.2 9.9-22.1 22.1-22.1h63.8c36 0 67.6-28.2 72.2-65.4l31.4-181.3L309.2 124c3.2-26.9 27-48.9 53-48.9h575.9c12.2 0 22.1 9.9 22.1 22.1-0.2 12.4-10.1 22.3-22.3 22.3zM944.9 702.4c-9 10.2-20.9 15.6-34.3 15.6H343c-11.6 0-21-9.4-21-21s9.4-21 21-21h567.5c1 0 1.6-0.1 2.7-1.4 2.8-3.2 5.3-10.7 4.6-17.2l-56.5-363.9c-0.8-6.8-8.4-13-17.2-13.1L404.5 248c-11.6-0.8-20.3-10.9-19.4-22.5 0.8-11.1 10-19.5 21-19.5 0.5 0 1 0 1.6 0.1l438.1 32.4c28.7 0.2 53.9 22.1 57.2 48.9l56.6 364c2.2 18.6-3.5 38.2-14.7 51z" horiz-adv-x="1024" />
<glyph glyph-name="pengyouquaniconx" unicode="&#58884;" d="M512-128C229.223784-128 0 101.223784 0 384S229.223784 896 512 896s512-229.223784 512-512-229.223784-512-512-512z m-83.027027 792.838919L617.762595 439.351351 622.702703 651.58227A305.497946 305.497946 0 0 1 505.828324 674.594595c-25.849081 0-51.684324-3.26573-76.855351-9.755676zM262.918919 524.038919L553.513514 494.702703 406.140541 646.918919a291.964541 291.964541 0 0 1-97.017082-63.584865A288.422054 288.422054 0 0 1 262.918919 524.038919zM231.161081 300.972973L456.648649 489.804108 244.41773 494.702703A305.235027 305.235027 0 0 1 221.405405 377.869838c0-26.001297 3.279568-51.836541 9.755676-76.896865z m140.730811-166.054054L401.297297 425.513514 249.081081 278.168216a290.636108 290.636108 0 0 1 63.584865-97.044757A291.161946 291.161946 0 0 1 371.891892 134.918919z m146.265946-41.513514A309.829189 309.829189 0 0 1 595.027027 103.119568L406.237405 328.648649 401.297297 116.376216A306.162162 306.162162 0 0 1 518.171676 93.405405zM470.486486 273.297297l147.359136-152.216216a291.078919 291.078919 0 0 1 97.003243 63.626378c17.989189 17.712432 33.487568 37.638919 46.232216 59.225946L470.486486 273.297297z m96.864865 4.898595L779.596108 273.297297A305.152 305.152 0 0 1 802.594595 390.171676c0 25.91827-3.26573 51.767351-9.741838 76.855351L567.351351 278.195892zM652.052757 633.081081L622.702703 342.486486l152.216216 147.372973a290.428541 290.428541 0 0 1-63.584865 97.058595A288.823351 288.823351 0 0 1 652.038919 633.081081z" horiz-adv-x="1024" />
<glyph glyph-name="play_hovericon" unicode="&#59011;" d="M512 896c282.763636 0 512-229.236364 512-512s-229.236364-512-512-512S0 101.236364 0 384 229.236364 896 512 896z m182.760727-552.680727a46.545455 46.545455 0 0 1 0 81.361454l-311.086545 172.846546A23.272727 23.272727 0 0 1 349.090909 577.163636v-386.327272a23.272727 23.272727 0 0 1 34.583273-20.363637l311.086545 172.846546z" horiz-adv-x="1024" />
</font>
......
......@@ -5,7 +5,8 @@ import {Toast} from 'antd-mobile'
import {api, http} from "@/utils"
import {HeaderBar} from "@/common"
import {logout, updateUser} from '@/store/userAction'
import {compose} from "redux";
import {WithFullSize} from '@/HOCs'
class MyEdut extends PureComponent {
constructor(props) {
......@@ -107,7 +108,10 @@ class MyEdut extends PureComponent {
}
export default connect(
state => ({user: state.user}),
{logout, updateUser}
export default compose(
connect(
state => ({user: state.user}),
{logout, updateUser}
),
WithFullSize
)(MyEdut)
......@@ -3,9 +3,9 @@ import './button.scss'
import classnames from 'classnames'
const Button = ({children, active}) => {
const Button = ({children, active, ...rest}) => {
return (
<button className={classnames('custom-button', {active})}>
<button className={classnames('custom-button', {active})} {...rest}>
{children}
</button>
);
......
import {useEffect} from 'react'
export default function Effect(props) {
const {submitCount, isValid} = props.formik
const effect = () => {
if(submitCount > 0 && !isValid){
props.onSubmissionError()
}
}
useEffect(effect, [submitCount])
return null
}
\ No newline at end of file
......@@ -79,13 +79,13 @@ class VeriCodeInput extends Component {
}
sendSMS = () => {
const {action, tel, challenge} = this.props
if (!tel) {
const {action, tel, account, challenge} = this.props
if (!tel && !account) {
Toast.info('请输入手机号或邮箱地址')
return
}
http.post(`${api['passport-api']}/quick_sms`, {
phone_num: tel,
phone_num: tel || account,
action: action || 'login',
challenge
}).then(res => {
......
......@@ -9,7 +9,7 @@ import { Toast } from "antd-mobile";
import { HeaderBar, Captcha, ClearableInput } from "@/common";
import { validateTel, validateEmail, http, api } from "@/utils";
import { quickLogin } from '@/store/userAction';
import { isEmpty } from "lodash";
import Effect from '../common/Effect'
class ForgotPassword extends Component {
......@@ -34,12 +34,15 @@ class ForgotPassword extends Component {
})
}
}
onSubmissionError = () => {
const errors = Object.values(this.props.errors);
errors.length && Toast.info(errors[0], 2000, null, false)
}
render() {
const {
values,
errors
isValid
} = this.props
return (
<div className={'forgot-password'}>
......@@ -82,8 +85,9 @@ class ForgotPassword extends Component {
}}
/>
}
<Effect formik={this.props} onSubmissionError={this.onSubmissionError}/>
<Captcha getInstance={this.getCaptchaInstance} onVerify={this.onVerify}/>
<Button active={values.account && values.veriCode && isEmpty(errors)}>下一步</Button>
<Button active={isValid}>下一步</Button>
</Form>
</div>
</div>
......@@ -98,17 +102,17 @@ const formikConfig = {
account: '',
veriCode: ''
}),
validateOnchange: true,
validateOnChange: true,
validateOnBlur: true,
validate: values => {
let errors = {}
if (!validateTel(values.account) && !validateEmail(values.account)) {
errors.account = '请输入正确的手机号或邮箱地址'
}
values.veriCode.toString().length !== 6 && (errors.veriCode = '验证码格式不正确')
return errors
},
handleSubmit(values, {props}) {
let account, address
if (validateEmail(values.account)) {
......
......@@ -10,6 +10,7 @@ import SetPassword from './setPassword'
import BindingTel from './bindingTel'
import { connect } from "react-redux";
import { compose } from "redux";
import {api} from "@/utils";
import account from './account.png'
import qq from './qq.png'
......@@ -42,7 +43,7 @@ class Passport extends Component {
{
logo: sina,
text: '新浪',
url: `http://passport-test.julyedu.com/mob/sinalogin?redirect_url=${this.redirect_url}`
url: `${api['passport-api']}/mob/sinalogin?redirect_url=${this.redirect_url}`
},
]
}
......@@ -61,7 +62,8 @@ class Passport extends Component {
routeWhenUserLoggedIn = () => {
let {history} = this.props
if (Object.values(this.props.user.data).filter(item => !!item).length) {
let {data} = this.props.user
if (data && Object.values(data).filter(item => !!item).length) {
history.action === 'POP' && history.go(-1)
}
}
......
......@@ -13,6 +13,7 @@ import { compose } from 'redux';
import { isEmpty } from 'lodash'
import { Toast } from 'antd-mobile';
import { validateTel } from "@/utils";
import { HeaderBar } from "@/common";
class Login extends Component {
......@@ -33,7 +34,7 @@ class Login extends Component {
case '微信':
let {from} = location.state || {from: {pathname: '/'}}
const redirectURI = window.location.protocol + '//' + window.location.hostname + from.pathname
const redirectURI = window.location.origin + from.pathname
// alert(redirectURI)
window.location.assign(`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=${encodeURIComponent(redirectURI)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`)
......@@ -67,6 +68,7 @@ class Login extends Component {
} = this.props
return (
<div className='login'>
<HeaderBar title={'登录'} arrow={true}/>
<Header/>
<Form className="login-info">
<Field
......
......@@ -3,6 +3,7 @@ import './aist-share.scss'
import withFullSize from '@/HOCs/WithFullSize'
import { http, api, wxShare } from "@/utils";
import { getWXObject } from "@/utils/wechat/base";
import {Link} from "react-router-dom";
class AistShare extends PureComponent {
state = {
......@@ -17,7 +18,6 @@ class AistShare extends PureComponent {
action: 0
},
showShareCover: true,
id: '',
user: {
avatar: '',
name: '',
......@@ -35,7 +35,8 @@ class AistShare extends PureComponent {
course: {
title: data.course_title,
des: data.course_desc,
img: data.image_name
img: data.image_name,
id: data.course_id
},
user: {
avatar: data.avatar,
......@@ -69,15 +70,17 @@ class AistShare extends PureComponent {
<span className="username">{user.name}</span>
<span className="time">{user.time}</span>
</div>
<div className="course">
<div className="course-cover">
<img src={course.img} alt="课程封面"/>
</div>
<div className="course-info">
<div className="title">{course.title}</div>
<div className="des">{course.des}</div>
<Link to={{pathname: '/detail', search: `?id=${this.state.course.id}`}}>
<div className="course">
<div className="course-cover">
<img src={course.img} alt="课程封面"/>
</div>
<div className="course-info">
<div className="title">{course.title}</div>
<div className="des">{course.des}</div>
</div>
</div>
</div>
</Link>
<ul className="progress">
<li>
<div className="title">累计学习</div>
......
......@@ -80,7 +80,7 @@ class MyCourses extends PureComponent {
componentDidMount() {
this.props.switchTab(false)
this.props.fetchCoursesListIfNeeded();
this.props.fetchCoursesListIfNeeded()
}
componentWillUnmount() {
......@@ -89,7 +89,7 @@ class MyCourses extends PureComponent {
loadFunc = debounce(() => {
if (this.props.courseList.length % 10 === 0) {
this.props.fetchCoursesListIfNeeded();
this.props.fetchCoursesListIfNeeded()
}
}, 200)
......
import React, { Component } from 'react';
import React, { Component } from 'react'
import HeaderBar from '@/common/HeaderBar'
import './video.scss'
import { NavLink, Route, Redirect, Switch } from 'react-router-dom';
import { NavLink, Route, Redirect, Switch } from 'react-router-dom'
import { http, api, getParam } from '@/utils'
import Recommendation from './recommendation'
import VideoCatalog from './video-catalog'
import DatumCatalog from './datum-catalog'
import { Toast } from 'antd-mobile';
import { Toast } from 'antd-mobile'
import videojs from 'video.js'
import 'video.js/dist/video-js.min.css'
import { Modal } from "antd-mobile";
import { Modal } from "antd-mobile"
import { Loading } from '@/common'
import { connect } from "react-redux"
import jsCookie from 'js-cookie'
let alert = Modal.alert
function ProgressShareModal(props) {
return (
props.isShow &&
<div className='progress-share-modal-wrapper'>
<div className="progress-share-modal">
<div className="title">每日打卡</div>
<ul className="progress-container">
<li>
<div className="title">累计学习</div>
<div className="number"><span className='num'>{props.data.learn_day_count}</span>天</div>
</li>
<li>
<div className="title">行动力超过</div>
<div className="number"><span className='num'>{parseFloat(props.data.action_power)}</span>%
</div>
</li>
</ul>
<div className="share-container">
<div className="title">分享到</div>
<ul>
<li className='share-icon'>
<div className="icon"><i className='iconfont iconweixinzhifu'></i></div>
<div className='text'>微信好友</div>
</li>
<li className='share-icon'>
<div className="icon"><i className='iconfont iconpengyouquaniconx'></i></div>
<div className='text'>朋友圈</div>
</li>
</ul>
</div>
<i className="iconfont iconiconfront-2 close" onClick={props.closeShareModal}/>
</div>
</div>
)
}
class Video extends Component {
......@@ -22,6 +61,12 @@ class Video extends Component {
courseID
ws //websocket instance
timer
token
count
watchSec
previousPlaybackRate = 1
currentPlaybackRate = 1
reconnect = true
state = {
......@@ -35,7 +80,9 @@ class Video extends Component {
course: null,
salePrice: null,
vCourseId: null,
isLoading: true
isLoading: true,
isShowShareModal: false,
shareData: {}
}
......@@ -44,48 +91,90 @@ class Video extends Component {
this.setState({
courseId: this.courseID
})
this.token = jsCookie.get('token')
this.getVideoList()
this.getDatumCatalog()
this.setupWS()
// this.setupTimer()
}
sendStudyRecord = () => {
}
setupWS = () => {
this.ws = new WebSocket('ws://process-test.julyedu.com:9501');
this.ws.addEventListener('onmessage', event => {
console.log(event.data);
this.ws = new WebSocket('ws://process-test.julyedu.com:9502');
this.ws.addEventListener('error', () => {
this.ws = null
this.setupWS();
})
this.ws.addEventListener('open', () => {
console.log('open');
})
this.ws.addEventListener('error', () => {
console.log('error');
})
this.ws.addEventListener('close', () => {
console.log('close');
if(this.reconnect){
this.ws = null
this.setupWS()
}
clearInterval(this.timer)
})
this.ws.addEventListener('message', e => {
const data = JSON.parse(e.data);
data.code == 4040 && (this.reconnect = false)
})
}
sendMessage = message => {
if(this.player){
this.ws.send(JSON.stringify(message))
}
}
//视频结束请求接口
getShareProgressInfo = () => {
http.get(`${api['base-api']}/m/aist/share_data/${this.courseID}/${this.state.videoList[this.state.activeIndex]['id']}`)
.then(res => {
const {data} = res
if (data.errno == 200) {
this.setState({shareData: data.data, isShowShareModal: true})
}
})
}
//告诉服务端切换视频
countSchedule = () => {
this.sendMessage({
mtype: 'count_schedule',
uid: this.props.user.data.uid,
token: this.token,
platform: 5
})
}
sendWatchTime = (sec, rate) => {
const {videoList, activeIndex, vCourseId} = this.state
this.sendMessage({
mtype: 'watch_time',
rate,
time: sec,
video_id: videoList[activeIndex]['id'],
course_id: this.courseID,
v_course_id: vCourseId,
uid: this.props.user.data.uid,
token: this.token,
platform: 5
})
}
setupTimer = () => {
let count = 0
this.count = 0
this.watchSec = 0
clearInterval(this.timer)
this.timer = setInterval(() => {
if(this.player){
console.log(this.player);
console.log(this.player.paused());
if (this.player && this.player.player()) {
if (this.count === 5) {
this.sendWatchTime(this.watchSec, this.currentPlaybackRate)
this.count = this.watchSec = 0
} else {
!this.player.paused() && this.watchSec++
this.count++
}
}
},1000)
}, 1000)
}
......@@ -98,19 +187,20 @@ class Video extends Component {
textTrackDisplay: false,
posterImage: false,
errorDisplay: false,
playbackRates: ['0.75', '1', '1.5', '2'],
userActions: {
doubleClick: () => {
// this.player.pause()
console.log(this);
}
}
playbackRates: ['0.75', '1', '1.5', '2']
})
this.player.enableTouchActivity()
this.player.on('seeking', function () {
console.log('seeking');
this.player.on('ratechange', () => {
this.currentPlaybackRate = this.player.playbackRate()
this.sendWatchTime(this.watchSec, this.previousPlaybackRate)
this.count = this.watchSec = 0
this.previousPlaybackRate = this.currentPlaybackRate
})
this.player.on('ended', () => {
this.sendWatchTime(this.watchSec, this.currentPlaybackRate)
this.getShareProgressInfo()
clearInterval(this.timer)
})
console.log(this.player);
}
componentWillUnmount() {
......@@ -122,10 +212,20 @@ class Video extends Component {
this.ws = null
}
handleClick = index => {
selectVideo = index => {
if (this.hasAuth()) {
if (index === this.state.activeIndex) {
return
}
this.setPlayerSrc(this.state.videoList[index]['play_url'])
this.playVideo()
clearInterval(this.timer)
if (this.ws) {
this.countSchedule()
this.setupTimer()
}
}
this.setState({
activeIndex: index
......@@ -150,6 +250,10 @@ class Video extends Component {
isLoading: false
}),
() => {
if (this.state.course.is_aist) {
this.setupWS()
this.setupTimer()
}
if (this.lessonAvailable()) {
if (this.hasAuth(this.state.activeIndex)) {
Promise.resolve().then(() => {
......@@ -306,7 +410,7 @@ class Video extends Component {
<Route path={`${match.path}/video`} render={props => {
return <VideoCatalog
activeIndex={this.state.activeIndex}
handleClick={this.handleClick}
selectVideo={this.selectVideo}
videoCatalog={this.state.videoList}
{...props}/>
}}/>
......@@ -318,10 +422,17 @@ class Video extends Component {
return this.state.vCourseId ? <Recommendation {...props} vCourseId={this.state.vCourseId}/>
: null
}}/>
<ProgressShareModal isShow={this.state.isShowShareModal}
closeShareModal={() => this.setState({isShowShareModal: false})}
data={this.state.shareData}
/>
</div>
);
}
}
export default Video;
\ No newline at end of file
export default connect(
state => ({user: state.user}),
null
)(Video);
\ No newline at end of file
import React, { Component } from 'react';
import React, { Component } from 'react'
import './video-catalog.scss'
import classnames from 'classnames'
......@@ -6,7 +6,7 @@ import classnames from 'classnames'
class VideoCatalog extends Component {
handleClick = (i) => {
this.props.handleClick(i)
this.props.selectVideo(i)
}
render() {
......@@ -18,15 +18,24 @@ class VideoCatalog extends Component {
return (
<li key={item.id}
className={classnames({active: this.props.activeIndex === index})}
onClick={this.handleClick.bind(this, index)}
>
<span className="title">{item.name}</span>
<span className='duration'>{item.duration}</span>
<i className={classnames(`iconfont`,
[item.video_auth === 0
? 'iconiconfront-74'
: 'iconiconfront-35'],
)}/>
<div className="video-title" onClick={this.handleClick.bind(this, index)}>
<span className="title">{item.name}</span>
<span className='duration'>{item.duration}</span>
<i className={classnames(`iconfont`,
[item.video_auth === 0
? 'iconiconfront-74'
: 'iconplay_hovericon'],
)}/>
</div>
{
(item.practice && item.practice.qid) ? <div className="exercise">
课后练习:{item.practice.title}
<i className={classnames('iconfont', item.practice.is_tested ? 'iconiconfront-3' : 'iconiconfront-74')}/>
{/*<i className='iconfont iconiconfront-74'/>*/}
</div>
: null
}
</li>
)
})
......
.video-catalog {
& li:first-child{
border-top: 1px solid #E7EAF1;
}
li {
height: 44px;
padding: 0 15px;
line-height: 44px;
border-top: 1px solid #E7EAF1;
border-bottom: 1px solid #E7EAF1;
padding: 0 15px;
&.active {
background-color: #F5FBFF;
.title, .duration{
.title, .duration {
color: $active;
}
.video-title {
background-color: #F5FBFF;
}
.exercise{
border-top: 1px solid #E7EAF1;
}
}
.video-title {
height: 44px;
margin: 0 -15px;
padding: 0 15px;
.iconfont{
font-size: 22px;
}
}
.exercise {
padding-left: 15px;
height: 35px;
background: #F5FBFF;
margin-bottom: 15px;
line-height: 35px;
color: #000;
border-top: 1px solid transparent;
.iconfont {
font-size: 18px;
//font-weight: bold;
}
}
}
......
......@@ -36,7 +36,7 @@ $tabHeight: 44px;
margin-bottom: 20px;
}
@mixin button{
@mixin button {
display: block;
-webkit-appearance: none;
outline: none;
......@@ -47,6 +47,7 @@ $tabHeight: 44px;
font-size: 13px;
padding: 0 9px;
}
.btns {
width: 100%;
padding: 0 60px;
......@@ -54,12 +55,13 @@ $tabHeight: 44px;
justify-content: space-around;
}
.purchase-class{
.purchase-class {
@include button;
background-color: $white;
color: $color_FF4000;
}
.purchase-episode{
.purchase-episode {
@include button;
background-color: $bg_FF4000;
color: $white;
......@@ -90,6 +92,10 @@ $tabHeight: 44px;
display: inline-block;
height: $tabHeight;
font-size: $font_16;
border-bottom: 1px solid transparent;
&.active{
border-bottom: 1px solid $active;
}
}
}
......@@ -101,4 +107,125 @@ $tabHeight: 44px;
}
}
.progress-share-modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 290px;
height: 332px;
padding: 18px 15px;
background: url("./images/progress-share-bg.png");
background-size: contain;
& > .title {
font-size: 21px;
color: #00656F;
line-height: 30px;
text-align: center;
margin-bottom: 20px;
}
.progress-container {
display: flex;
justify-content: space-between;
margin-bottom: 20px;
li {
flex: 1;
.title {
font-size: 14px;
color: #00838F;
line-height: 20px;
text-align: center;
flex: 1;
margin-bottom: 10px;
}
.number {
font-size: 15px;
color: #00656F;
text-align: center;
.num {
font-size: 33px;
color: #00656F;
}
}
}
}
.share-container {
.title {
position: relative;
text-align: center;
font-size: 14px;
color: #00838F;
margin-bottom: 25px;
&::before {
position: absolute;
top: 50%;
left: 30px;
transform: translateY(-50%);
content: '';
display: block;
width: 70px;
height: 1px;
background: #77c4bf;
}
&::after {
position: absolute;
top: 50%;
right: 30px;
transform: translateY(-50%);
content: '';
display: block;
width: 70px;
height: 1px;
background: #77c4bf;
}
}
ul {
display: flex;
justify-content: space-around;
padding: 0 20px;
text-align: center;
li {
font-size: 12px;
color: #00838F;
.iconfont {
font-size: 40px;
color: #00838f;
}
}
}
}
.close {
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: -63px;
color: #fff;
font-size: 30px;
}
&-wrapper {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
touch-action: none;
z-index: 100;
}
}
}
\ No newline at end of file
......@@ -12,33 +12,23 @@ function RouteMiddlePage(props) {
useEffect(() => {
let {user, location, history} = props
if (history.action === 'POP') {
history.goBack();
return
}
if (!isLoading) {
return
}
if (!user.isFetching) {
if (user.hasError) {
history.replace('/passport', {from: location})
setLoadingState(false)
} else {
let {data} = user || {
data: {
username: '',
avatar: '',
isVip: false,
token: '',
email: '',
uid: ''
}
}
if (Object.values(data).every(item => !!item).length !== 0) {
let {data} = user || {data: {}}
if (data && Object.values(data).every(item => !!item)) {
history.replace(location.pathname)
setLoadingState(false)
}else{
history.replace('/passport', {from: location})
}
}
}
......
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