Commit 0f7d4c66 by xuzhenghua

detail

parents 3a1d0878 f8861e99
......@@ -1443,6 +1443,20 @@
"@types/unist": "*"
}
},
"@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==",
"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",
"url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0"
}
},
"@webassemblyjs/ast": {
"version": "1.7.11",
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.7.11.tgz",
......@@ -1678,6 +1692,16 @@
"resolved": "https://registry.npmjs.org/address/-/address-1.0.3.tgz",
"integrity": "sha512-z55ocwKBRLryBs394Sm3ushTtBeg6VAeuku7utSoSnsJKvKcnXFIyC6vh27n3rXyxSgkJBBCAvyOn7gSUcTYjg=="
},
"aes-decrypter": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.0.0.tgz",
"integrity": "sha1-eEihwUW5/b9Xrj4rWxvHzwZEqPs=",
"requires": {
"commander": "^2.9.0",
"global": "^4.3.2",
"pkcs7": "^1.0.2"
}
},
"ajv": {
"version": "6.10.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.0.tgz",
......@@ -3727,6 +3751,11 @@
"randomfill": "^1.0.3"
}
},
"crypto-js": {
"version": "3.1.9-1",
"resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-3.1.9-1.tgz",
"integrity": "sha1-/aGedh/Ad+Af+/3G6f38WeiAbNg="
},
"css-animation": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/css-animation/-/css-animation-1.5.0.tgz",
......@@ -4382,6 +4411,11 @@
"entities": "^1.1.1"
}
},
"dom-walk": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.1.tgz",
"integrity": "sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg="
},
"domain-browser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
......@@ -5613,6 +5647,14 @@
}
}
},
"for-each": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
"requires": {
"is-callable": "^1.1.3"
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
......@@ -6370,6 +6412,22 @@
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz",
"integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs="
},
"global": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz",
"integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=",
"requires": {
"min-document": "^2.19.0",
"process": "~0.5.1"
},
"dependencies": {
"process": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz",
"integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8="
}
}
},
"global-modules": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz",
......@@ -6959,6 +7017,11 @@
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
"integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
},
"individual": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz",
"integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c="
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
......@@ -7178,6 +7241,11 @@
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-function": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.1.tgz",
"integrity": "sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU="
},
"is-generator-fn": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-1.0.0.tgz",
......@@ -8446,6 +8514,11 @@
"array-includes": "^3.0.3"
}
},
"keycode": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz",
"integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ="
},
"killable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
......@@ -8800,6 +8873,14 @@
"yallist": "^3.0.2"
}
},
"m3u8-parser": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.3.0.tgz",
"integrity": "sha512-bVbjuBMoVIgFL1vpXVIxjeaoB5TPDJRb0m5qiTdM738SGqv/LAmsnVVPlKjM4fulm/rr1XZsKM+owHm+zvqxYA==",
"requires": {
"global": "^4.3.2"
}
},
"make-dir": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
......@@ -9108,6 +9189,14 @@
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz",
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
},
"min-document": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz",
"integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=",
"requires": {
"dom-walk": "^0.1.0"
}
},
"mini-css-extract-plugin": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz",
......@@ -9230,6 +9319,15 @@
"run-queue": "^1.0.3"
}
},
"mpd-parser": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.7.0.tgz",
"integrity": "sha512-nkzVIkecaDz3q7p4ToN3GR0FV2Odbh0w2sJ8ijsyw79JcBrJoUD3KHIiI8gL0hEDlex7mrVpTxXBsRHowUBmPw==",
"requires": {
"global": "^4.3.2",
"url-toolkit": "^2.1.1"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
......@@ -9254,6 +9352,11 @@
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz",
"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=="
},
"nan": {
"version": "2.13.2",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.13.2.tgz",
......@@ -9898,6 +10001,15 @@
"is-glob": "^2.0.0"
}
},
"parse-headers": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.2.tgz",
"integrity": "sha512-/LypJhzFmyBIDYP9aDVgeyEb5sQfbfY5mnDq4hVhlQ69js87wXfmEI5V3xI6vvXasqebp0oCytYFLxsBVfCzSg==",
"requires": {
"for-each": "^0.3.3",
"string.prototype.trim": "^1.1.2"
}
},
"parse-json": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
......@@ -10011,6 +10123,11 @@
"pinkie": "^2.0.0"
}
},
"pkcs7": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.2.tgz",
"integrity": "sha1-ttulJ1KMKUK/wSLOLa/NteWQdOc="
},
"pkg-dir": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz",
......@@ -12121,6 +12238,14 @@
"aproba": "^1.1.1"
}
},
"rust-result": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
"integrity": "sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I=",
"requires": {
"individual": "^2.0.0"
}
},
"rxjs": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz",
......@@ -12134,6 +12259,14 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"safe-json-parse": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz",
"integrity": "sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw=",
"requires": {
"rust-result": "^1.0.0"
}
},
"safe-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
......@@ -13069,6 +13202,16 @@
}
}
},
"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=",
"requires": {
"define-properties": "^1.1.2",
"es-abstract": "^1.5.0",
"function-bind": "^1.0.2"
}
},
"string_decoder": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz",
......@@ -13601,6 +13744,11 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
},
"tsml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tsml/-/tsml-1.0.1.tgz",
"integrity": "sha1-ifghi52eJX9H1/a1bQHFpNLGj8M="
},
"tty-browserify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
......@@ -13884,6 +14032,11 @@
"requires-port": "^1.0.0"
}
},
"url-toolkit": {
"version": "2.1.6",
"resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.1.6.tgz",
"integrity": "sha512-UaZ2+50am4HwrV2crR/JAf63Q4VvPYphe63WGeoJxeu8gmOm0qxPt+KsukfakPNrX9aymGNEkkaoICwn+OuvBw=="
},
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
......@@ -14006,6 +14159,35 @@
"unist-util-stringify-position": "^1.1.1"
}
},
"video.js": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.5.4.tgz",
"integrity": "sha512-+U3FyLVFbnJdEC6TVMv8U75c8VM00vmVY8TSfFthnvo7/6rz3LFg2Pd3TTGNbV2pEmBhkLLYO+dvmqMNUyc2ZA==",
"requires": {
"@babel/runtime": "^7.2.0",
"@videojs/http-streaming": "1.9.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",
"xhr": "2.4.0"
}
},
"videojs-font": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.1.0.tgz",
"integrity": "sha512-rxB68SVgbHD+kSwoNWNCHicKJuR2ga3bGfvGxmB+8fupsiLbnyCwTBVtrZUq4bZnD64mrKP1DxHiutxwrs59pQ=="
},
"videojs-vtt.js": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.14.1.tgz",
"integrity": "sha512-YxOiywx6N9t3J5nqsE5WN2Sw4CSqVe3zV+AZm2T4syOc2buNJaD6ZoexSdeszx2sHLU/RRo2r4BJAXFDQ7Qo2Q==",
"requires": {
"global": "^4.3.1"
}
},
"vm-browserify": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
......@@ -14736,6 +14918,17 @@
"resolved": "https://registry.npmjs.org/x-is-string/-/x-is-string-0.1.0.tgz",
"integrity": "sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI="
},
"xhr": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/xhr/-/xhr-2.4.0.tgz",
"integrity": "sha1-4W5mpF+GmGHu76tBbV7/ci3ECZM=",
"requires": {
"global": "~4.3.0",
"is-function": "^1.0.1",
"parse-headers": "^2.0.0",
"xtend": "^4.0.0"
}
},
"xml-name-validator": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz",
......
......@@ -17,6 +17,7 @@
"babel-preset-react-app": "^7.0.2",
"bfj": "6.1.1",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"crypto-js": "^3.1.9-1",
"css-loader": "1.0.0",
"date-fns": "^1.30.1",
"dotenv": "6.0.0",
......@@ -70,6 +71,7 @@
"style-loader": "0.23.1",
"terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2",
"video.js": "^7.5.4",
"webpack": "4.28.3",
"webpack-dev-server": "3.1.14",
"webpack-manifest-plugin": "2.0.4",
......
import React, {Component} from 'react'
import React, { Component } from 'react'
import Routes from './router'
import cookie from 'js-cookie'
import {api} from '@/utils'
import { http, api } from '@/utils';
import { connect } from 'react-redux';
import { setCurrentUser } from '@/store/userAction';
//拦截ajax请求,返回mock数据
/*import mock from '@/utils/mock'
......@@ -14,15 +17,57 @@ import './assets/css/index.scss';
// iconfont
import './assets/font/iconfont.css';
class App extends Component {
componentDidMount() {
export default class App extends Component{
componentDidMount(){
//平台信息
cookie.set('plat', '5')
http.get(`${api.home}/m/user_info`).then(res => {
this.props.setCurrentUser(this.storeUser(res))
})
}
storeUser = res => {
let payload
if (res.data.code === 200) {
const {
msg, data: {
avatar_file: avatar,
user_name: username,
is_vip: isVIP,
uid
}
} = res.data
payload = {
hasError: false,
msg,
data: {
username,
isVIP,
avatar,
uid
}
}
render(){
} else {
payload = {
hasError: true,
msg: res.data.msg
}
}
return payload
}
render() {
return <Routes/>
}
}
export default connect(
null,
{setCurrentUser}
)(App)
\ No newline at end of file
import React, { Component } from "react"
import React, { PureComponent } from "react"
import './accountLogin.scss'
import { Link } from "react-router-dom";
import { withFormik, FastField, Form } from "formik";
import { compose } from 'redux';
import { accountLogin } from '@/store/userAction';
import { connect } from "react-redux";
import Header from "../common/Header";
......@@ -11,8 +14,7 @@ import PasswordInput from '../common/passwordInput'
// import VeriCodeButton from '../common/veriCodeInput'
// import LoginWays from '../common/LoginWays'
class AccountLogin extends Component {
class AccountLogin extends PureComponent {
render() {
return (
......@@ -40,6 +42,7 @@ class AccountLogin extends Component {
render={({field}) => (
<PasswordInput
{...field}
autoComplete={'on'}
placeholder={'密码'}
/>
)}
......@@ -58,8 +61,24 @@ const formikConfig = {
account: '',
password: ''
}),
handleSubmit(values) {
console.log(values)
handleSubmit(values, formikBag) {
const {account: username, password} = values
const {props, props: {history}} = formikBag
props.accountLogin({
username, password
}).then(res => {
if (!res.hasError) {
let {from} = props.location.state || {from: {pathname: '/'}}
history.push(from.pathname)
}
})
}
}
export default withFormik(formikConfig)(AccountLogin)
export default compose(
connect(
state => ({user: state.user}),
{accountLogin}
),
withFormik(formikConfig)
)(AccountLogin)
import aes from 'crypto-js/aes'
import Crypto from 'crypto-js'
const key = Crypto.enc.Hex.parse('C7D590D00FA968A261BDD5B6CD40DDC2C0561338BF8B9197')
const iv = Crypto.enc.Hex.parse('19513F90B7A8875E469E82195F90EE99')
function encrypt(message) {
return aes.encrypt(message, key, {
iv,
mode: Crypto.mode.CBC,
}).toString()
}
function decrypt(encrypted) {
return Crypto.enc.Utf8.stringify(aes.decrypt(encrypted, key, {iv}))
}
export { encrypt, decrypt }
\ No newline at end of file
......@@ -17,12 +17,10 @@ class ForgotPassword extends Component {
}
setTel = (val) => {
console.log(val)
this.setState({tel: val})
}
setVerificationCode = (val) => {
console.log(val)
this.setState({verificationCode: val});
}
......
......@@ -18,7 +18,6 @@ class SetPassword extends Component {
handleChange = (val) => {
console.log(val)
this.setState({password: val});
}
......
export const login = (userInfo) => ({
type: 'LOGIN',
userInfo
})
export const logout = () => ({
type: 'LOGOUT'
})
export const requestLogin = payload => dispatch => {
}
\ No newline at end of file
const initialState = {
userName: '',
avatar: '',
uid: '',
isVIP: false
}
const userInfo = (state = initialState, action) => {
switch (action.type) {
case 'LOGIN':
return {
...state,
...action.userInfo
}
default:
return state
}
}
export default userInfo
\ No newline at end of file
.datum-catalog {
.prompt {
height: 30px;
line-height: 30px;
font-size: $font_12;
color: $color_333;
background-color: #FFF4CE;
text-align: center;
}
.file-name {
padding: 15px;
padding-bottom: 0;
}
& .file-name:last-of-type {
padding-bottom: 15px;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './datum-catalog.scss'
import { Accordion } from "antd-mobile";
class DatumCatalog extends Component {
static defaultProps = {
datum: [{
dir_name: '',
files: [{
file_name: '',
file_id: 0
}]
}]
}
render() {
return (
<div className='datum-catalog'>
<p className='prompt'>课程资料请到PC端播放页下载</p>
<Accordion>
{
this.props.datum.map((item, index) => {
return (
<Accordion.Panel header={item.dir_name} key={index}>
{
item.files.map(item => {
return (
<div key={item.file_id} className='file-name'>
{item.file_name}
</div>
)
})
}
</Accordion.Panel>
)
})
}
</Accordion>
</div>
);
}
}
export default DatumCatalog;
\ No newline at end of file
import React, { Component } from 'react';
import HeaderBar from '@/common/HeaderBar'
import './video.scss'
import { NavLink, Route } from 'react-router-dom';
import { http, api } from '@/utils'
import Recommendation from './recommendation'
import VideoCatalog from './video-catalog'
import DatumCatalog from './datum-catalog'
import { Toast } from 'antd-mobile';
import videojs from 'video.js'
import 'video.js/dist/video-js.min.css'
// import 'video.scss'
class Video extends Component {
video;
state = {
title: '视频',
courseId: 140,
video_catalog: [],
datum: []
}
componentDidMount() {
window.HELP_IMPROVE_VIDEOJS = false;
videojs(this.video, {
controls: true,
autoplay: true,
preload: 'auto',
bigPlayButton: true,
textTrackDisplay: false,
posterImage: false,
errorDisplay: false,
}, function () {
this.log.debug()
})
this.getVideoCatalog()
this.getDatumCatalog()
}
getVideoCatalog = () => {
http.get(`${api.home}/m/course/play/40`)
.then(res => {
const data = res.data
if (data.code === 200) {
this.setState({
video_catalog: data.data.lessons
})
} else {
Toast.info(data.msg)
}
})
}
getDatumCatalog() {
http.get(`${api.home}/m/course/data/40`)
.then(res => {
const data = res.data
if (data.code === 200) {
this.setState({
datum: data.data
})
} else {
Toast.info(data.msg)
}
})
}
render() {
let {match} = this.props
return (
<div className='play'>
<HeaderBar title={this.state.title}/>
<div className="video">
<video className={'video-js'} ref={el => this.video = el}>
<source src='/v2/ts/40/191/175d6e5a.m3u8' type='application/x-mpegURL'/>
</video>
</div>
<div className='tab'>
<div>
<NavLink to={`${match.url}/video`}
replace
activeClassName='active'
>视频</NavLink>
</div>
<div>
<NavLink to={`${match.url}/datum`}
replace
activeClassName='active'
>资料</NavLink>
</div>
</div>
{/*<Route path={`${match.path}/video`} render={props => {
return <VideoCatalog videoCatalog={this.state.video_catalog} {...props}/>
}}/>
<Route path={`${match.path}/datum`} render={props => {
return <DatumCatalog {...props} datum={this.state.datum}/>
}}/>
<Route render={props => {
return <Recommendation {...props} courseId={this.state.courseId}/>
}}/>*/}
</div>
);
}
}
export default Video;
\ No newline at end of file
import React, { Component } from 'react';
import './recommendation.scss'
import { http, api } from '@/utils'
import { Toast } from "antd-mobile";
import {VList} from '@/common';
const Bottom = ({item}) => {
return (
<div className='bottom'>
<span className='price'>¥{item.price1}</span>
<span className='stale-price'>¥{item.price0}</span>
</div>
)
}
class Recommendation extends Component {
state = {
num: 10,
list: []
}
componentDidMount() {
http.get(`${api.home}/m/play/recommend_course/${this.props.courseId}?num=${this.state.num}`)
.then(res => {
const data = res.data
if(data.code === 200){
this.setState({
list: data.data
})
}else {
Toast.info(data.msg)
}
})
}
handleClick = id => {
console.log(id)
}
render() {
return (
<div className='recommendation'>
<div className={'title'}>相关推荐</div>
<ul>
{
this.state.list.map(item => {
const Info = (
<div className="info">
<p className='title'>{item.course_title}</p>
<p className='des'>{item.simpledescription}</p>
<Bottom
item={item}
/>
</div>
)
return (
<VList
key={item.course_id}
img={item.image_name}
handleClick={this.handleClick}
info={Info}
id={item.course_id}
/>
)
})
}
</ul>
</div>
);
}
}
export default Recommendation;
\ No newline at end of file
.recommendation {
padding-top: 20px;
& > .title {
font-size: $font_16;
padding-left: 15px;
}
.info {
display: flex;
flex-wrap: wrap;
.des {
font-size: $font_14;
line-height: 16px;
align-self: flex-start;
}
.price {
color: $red;
font-size: $font_16;
margin-right: 14px;
}
.stale-price {
text-decoration: line-through;
color: $color_999;
font-size: $font_12;
}
.bottom {
align-self: flex-end;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './video-catalog.scss'
import classnames from 'classnames'
class VideoCatalog extends Component {
render() {
return (
<div className='video-catalog'>
<ul>
{
this.props.videoCatalog.map(item => {
return (
<li key={item.id}>
<span className="title">{item.name}</span>
<span className='duration'>{item.duration}</span>
<i className={classnames(`iconfont`,
[item.video_auth === 0
? 'iconiconfront-74'
: 'iconiconfront-35'],
)}/>
</li>
)
})
}
</ul>
</div>
);
}
}
export default VideoCatalog;
\ No newline at end of file
.video-catalog {
li {
height: 44px;
padding: 0 15px;
line-height: 44px;
border-top: 1px solid #E7EAF1;
border-bottom: 1px solid #E7EAF1;
&.active {
background-color: #F5FBFF;
.title, .duration{
color: $active;
}
}
}
.title {
display: inline-block;
width: 50%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
font-size: $font_14;
margin-right: 26px;
}
.duration {
display: inline-block;
font-size: 11px;
overflow: hidden;
}
.iconfont {
float: right;
}
}
\ No newline at end of file
$tabHeight: 44px;
.play {
.video {
width: 100%;
height: 215px;
background-color: $black;
video {
width: 100%;
height: 100%;
}
}
.tab {
height: $tabHeight;
max-height: $tabHeight;
line-height: $tabHeight;
text-align: center;
background: #F7F9FC;
flex: 1 0 auto;
display: flex;
justify-content: center;
& > div {
flex: 1 0 auto;
}
a {
display: inline-block;
height: $tabHeight;
font-size: $font_16;
}
}
.active {
color: $active;
border-bottom: 1px solid $active;
}
}
\ No newline at end of file
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux'
import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux'
import thunk from 'redux-thunk'
import logger from 'redux-logger'
import rootReducers from './store'
import App from './App'
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const store = createStore(
rootReducers,
composeEnhancers(
applyMiddleware(thunk, logger)
)
)
......
import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import RouterConfig from './router-config'
import PrivateRoute from './privateRoute'
export default function () {
......@@ -8,9 +9,9 @@ export default function () {
<Router>
<Switch>
{RouterConfig.map((item, index) => {
let {CustomRoute, ...rest} = item
if (CustomRoute) {
return <CustomRoute {...rest}/>
let {isPrivate, ...rest} = item
if (isPrivate) {
return <PrivateRoute {...rest} key={index}/>
} else {
return (
<Route {...rest} key={index}/>
......
import React from 'react';
import { Route, Redirect } from "react-router-dom";
import { connect } from "react-redux";
import jsCookie from 'js-cookie'
const PrivateRoute = ({component: Component, path, user, ...rest}) => {
let authenticated = jsCookie.get('token') && jsCookie.get('uid')
return (
<Route {...rest} render={props => {
return authenticated
? <Component {...props}/>
: <Redirect to={{
pathname: '/passport/account-login',
state: {from: props.location}
}}/>
}}/>
);
};
export default connect(
state => ({user: state.user}),
null
)(PrivateRoute);
\ No newline at end of file
......@@ -17,6 +17,7 @@ import Passport from '@/components/passport'
const Coupons = loadable(() => import(/* webpackChunkName: 'coupons'*/ '@/components/coupons'))
const Study = loadable(() => import(/* webpackChunkName: 'study'*/'@/components/study'))
const Video = loadable(() => import(/* webpackChunkName: 'video'*/'@/components/video'))
export default [
{
......@@ -67,7 +68,8 @@ export default [
},
{
path: '/coupons',
component: Coupons
component: Coupons,
isPrivate: true
},
{
path: '/shopcart',
......@@ -81,4 +83,8 @@ export default [
path: '/passport',
component: Passport
},
{
path: '/play',
component: Video
},
]
\ No newline at end of file
......@@ -8,10 +8,12 @@ module.exports = function (app) {
config[item]['development'], {
target: config[item]['test'],
changeOrigin: true,
// secure: false,
pathRewrite: {
[`^${config[item]['development']}`]: ''
},
...item['proxy']
cookieDomainRewrite: 'localhost',
...config[item]['proxy']
}
))
})
......
import { combineReducers } from 'redux';
import myCourses from '@/components/study/myCourses/reducers'
import courseInfo from '@/components/detail/reducers'
import user from './userReducer'
const reducer = combineReducers({
myCourses,
courseInfo
courseInfo,
user
});
export default reducer;
\ No newline at end of file
import { http, api } from '@/utils';
import { encrypt } from '@/components/passport/encryption';
import jsCookie from 'js-cookie'
const accountLogin = user => dispatch => {
return http.post(`${api['passport-api']}/user_login`, {
user_name: user.username,
password: encrypt(user.password),
is_encrypt: 1
}).then(res => {
const data = res.data
let payload
if (data.errno === 0) {
const {user_name: username, avatar_file: avatar, ...rest} = data.data.user_info
payload = {
hasError: false,
msg: data.msg,
data: {username, avatar, ...rest}
}
} else {
payload = {
hasError: true,
msg: data.msg
}
}
dispatch(setCurrentUser(payload))
return payload
})
}
/*
const CAPTCHA_LOGIN = 'CAPTCHA_LOGIN'
const captchaLogin = payload => dispatch => {
return http.post(`${api['passport-api']}/`)
}
*/
const SET_CURRENT_USER = 'SET_CURRENT_USER'
const setCurrentUser = payload => ({
type: SET_CURRENT_USER,
payload
})
const LOGOUT = 'LOGOUT'
const logout = () => dispatch => {
jsCookie.remove('token')
jsCookie.remove('uid')
dispatch(setCurrentUser({}))
}
export {
accountLogin,
SET_CURRENT_USER,
setCurrentUser
}
\ No newline at end of file
import { SET_CURRENT_USER } from '@/store/userAction';
const initialState = {
hasError: false,
msg: '',
data: {
username: '',
avatar: '',
isVip: false,
token: '',
email: '',
uid: ''
}
}
export default function (state = initialState, action) {
switch (action.type) {
case SET_CURRENT_USER:
return action.payload
default:
return state
}
}
\ No newline at end of file
export { default as http } from './http'
export { default as api } from './api'
// 计算时间相差fn(过去距离当前时间)
export const computingTime = (pastTime) => {
var currentTime = (new Date()).getTime(),
distanceTime = currentTime - pastTime,
// 计算相差天数
days = Math.floor(distanceTime / (24 * 3600 * 1000)),
// 计算相差小时数
leave1 = distanceTime % (24 * 3600 * 1000),
hours = Math.floor(leave1 / (3600 * 1000)),
// 计算相差分钟数
leave2 = leave1 % (3600 * 1000),
minutes = Math.floor(leave2 / (60 * 1000)),
// 计算相差毫秒数
leave3 = leave2 % (60 * 1000),
seconds = Math.round(leave3 / 1000),
// 处理返回格式
dayStr = days <= 0 ? "" : days + "天",
hourStr = hours <= 0 ? "" : hours + "小时",
minuteStr = minutes <= 0 ? "" : minutes + "分钟",
secondStr = (days <= 0 && hours <= 0 && minutes <= 0) ? "刚刚" : "前";
// secondStr=seconds==0?"":seconds+"秒";
if (days >= 1) {
return dayStr + '前';
} else {
return dayStr + hourStr + minuteStr + secondStr;
}
}
// 时间倒计时 (未来距离现在)
export const timeDown = (endDate) => {
var now = new Date();
var leftTime = endDate - now.getTime();
var leftsecond = parseInt(leftTime / 1000);
var day1 = Math.floor(leftsecond / (60 * 60 * 24));
var hour = Math.floor((leftsecond - day1 * 24 * 60 * 60) / 3600);
var minute = Math.floor((leftsecond - day1 * 24 * 60 * 60 - hour * 3600) / 60);
var second = Math.floor(leftsecond - day1 * 24 * 60 * 60 - hour * 3600 - minute * 60);
hour = hour >= 10 ? hour : '0' + hour;
minute = minute >= 10 ? minute : '0' + minute;
second = second >= 10 ? second : '0' + second;
return day1 + '天' + hour + ':' + minute + ':' + second;
return leftTime;
}
export { html }
export const isPhone = ($poneInput) => {
var myreg = /^[1][3,4,5,7,8][0-9]{9}$/;
if (!myreg.test($poneInput)) {
return true;
} else {
return false;
}
}
export const getParam = (key, str) => {
const _s = str ? str : location.href;
......@@ -58,3 +11,13 @@ export const getParam = (key, str) => {
let found;
return (found = re.exec(_s)) ? found[2] : null;
}
const html = content => ({__html: htmlDecode(content)})
const htmlDecode = content => {
let e = document.createElement('div');
e.innerHTML = content;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
......@@ -11,6 +11,20 @@ const config = {
production: 'https://search.julyedu.com',
proxy: {}
},
v2: {
development: '/v2',
test: 'https://v2.julyedu.com',
production: 'https://search.julyedu.com',
proxy: {
secure: false,
}
},
'passport-api': {
development: '/passport-api',
test: 'http://passport-test.julyedu.com',
production: 'http://passport.julyedu.com',
proxy: {}
},
}
module.exports = config
\ No newline at end of file
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