Commit f67e6ca8 by zhanghaozhe

study redux

parent 71bac820
...@@ -5724,7 +5724,8 @@ ...@@ -5724,7 +5724,8 @@
}, },
"ansi-regex": { "ansi-regex": {
"version": "2.1.1", "version": "2.1.1",
"bundled": true "bundled": true,
"optional": true
}, },
"aproba": { "aproba": {
"version": "1.2.0", "version": "1.2.0",
...@@ -5742,11 +5743,13 @@ ...@@ -5742,11 +5743,13 @@
}, },
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true "bundled": true,
"optional": true
}, },
"brace-expansion": { "brace-expansion": {
"version": "1.1.11", "version": "1.1.11",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"balanced-match": "^1.0.0", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
...@@ -5759,15 +5762,18 @@ ...@@ -5759,15 +5762,18 @@
}, },
"code-point-at": { "code-point-at": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"console-control-strings": { "console-control-strings": {
"version": "1.1.0", "version": "1.1.0",
"bundled": true "bundled": true,
"optional": true
}, },
"core-util-is": { "core-util-is": {
"version": "1.0.2", "version": "1.0.2",
...@@ -5870,7 +5876,8 @@ ...@@ -5870,7 +5876,8 @@
}, },
"inherits": { "inherits": {
"version": "2.0.3", "version": "2.0.3",
"bundled": true "bundled": true,
"optional": true
}, },
"ini": { "ini": {
"version": "1.3.5", "version": "1.3.5",
...@@ -5880,6 +5887,7 @@ ...@@ -5880,6 +5887,7 @@
"is-fullwidth-code-point": { "is-fullwidth-code-point": {
"version": "1.0.0", "version": "1.0.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"number-is-nan": "^1.0.0" "number-is-nan": "^1.0.0"
} }
...@@ -5892,17 +5900,20 @@ ...@@ -5892,17 +5900,20 @@
"minimatch": { "minimatch": {
"version": "3.0.4", "version": "3.0.4",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"brace-expansion": "^1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {
"version": "0.0.8", "version": "0.0.8",
"bundled": true "bundled": true,
"optional": true
}, },
"minipass": { "minipass": {
"version": "2.3.5", "version": "2.3.5",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"yallist": "^3.0.0" "yallist": "^3.0.0"
...@@ -5919,6 +5930,7 @@ ...@@ -5919,6 +5930,7 @@
"mkdirp": { "mkdirp": {
"version": "0.5.1", "version": "0.5.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"minimist": "0.0.8" "minimist": "0.0.8"
} }
...@@ -5991,7 +6003,8 @@ ...@@ -5991,7 +6003,8 @@
}, },
"number-is-nan": { "number-is-nan": {
"version": "1.0.1", "version": "1.0.1",
"bundled": true "bundled": true,
"optional": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
...@@ -6001,6 +6014,7 @@ ...@@ -6001,6 +6014,7 @@
"once": { "once": {
"version": "1.4.0", "version": "1.4.0",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"wrappy": "1" "wrappy": "1"
} }
...@@ -6076,7 +6090,8 @@ ...@@ -6076,7 +6090,8 @@
}, },
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"bundled": true "bundled": true,
"optional": true
}, },
"safer-buffer": { "safer-buffer": {
"version": "2.1.2", "version": "2.1.2",
...@@ -6106,6 +6121,7 @@ ...@@ -6106,6 +6121,7 @@
"string-width": { "string-width": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"code-point-at": "^1.0.0", "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0", "is-fullwidth-code-point": "^1.0.0",
...@@ -6123,6 +6139,7 @@ ...@@ -6123,6 +6139,7 @@
"strip-ansi": { "strip-ansi": {
"version": "3.0.1", "version": "3.0.1",
"bundled": true, "bundled": true,
"optional": true,
"requires": { "requires": {
"ansi-regex": "^2.0.0" "ansi-regex": "^2.0.0"
} }
...@@ -6161,11 +6178,13 @@ ...@@ -6161,11 +6178,13 @@
}, },
"wrappy": { "wrappy": {
"version": "1.0.2", "version": "1.0.2",
"bundled": true "bundled": true,
"optional": true
}, },
"yallist": { "yallist": {
"version": "3.0.3", "version": "3.0.3",
"bundled": true "bundled": true,
"optional": true
} }
} }
}, },
...@@ -8251,6 +8270,11 @@ ...@@ -8251,6 +8270,11 @@
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
"integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==" "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw=="
}, },
"js-cookie": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.0.tgz",
"integrity": "sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s="
},
"js-levenshtein": { "js-levenshtein": {
"version": "1.1.6", "version": "1.1.6",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
...@@ -11352,6 +11376,14 @@ ...@@ -11352,6 +11376,14 @@
"resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz",
"integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw=="
}, },
"react-infinite-scroller": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/react-infinite-scroller/-/react-infinite-scroller-1.2.4.tgz",
"integrity": "sha512-/oOa0QhZjXPqaD6sictN2edFMsd3kkMiE19Vcz5JDgHpzEJVqYcmq+V3mkwO88087kvKGe1URNksHEOt839Ubw==",
"requires": {
"prop-types": "^15.5.8"
}
},
"react-is": { "react-is": {
"version": "16.8.6", "version": "16.8.6",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.8.6.tgz",
......
...@@ -37,8 +37,10 @@ ...@@ -37,8 +37,10 @@
"jest-pnp-resolver": "1.0.2", "jest-pnp-resolver": "1.0.2",
"jest-resolve": "23.6.0", "jest-resolve": "23.6.0",
"jest-watch-typeahead": "^0.2.1", "jest-watch-typeahead": "^0.2.1",
"js-cookie": "^2.2.0",
"less": "^3.9.0", "less": "^3.9.0",
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"lodash": "^4.17.11",
"mini-css-extract-plugin": "0.5.0", "mini-css-extract-plugin": "0.5.0",
"node-sass": "^4.11.0", "node-sass": "^4.11.0",
"optimize-css-assets-webpack-plugin": "5.0.1", "optimize-css-assets-webpack-plugin": "5.0.1",
...@@ -52,6 +54,7 @@ ...@@ -52,6 +54,7 @@
"react-app-polyfill": "^0.2.2", "react-app-polyfill": "^0.2.2",
"react-dev-utils": "^8.0.0", "react-dev-utils": "^8.0.0",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"react-infinite-scroller": "^1.2.4",
"react-lazy-load": "^3.0.13", "react-lazy-load": "^3.0.13",
"react-mobile-swiper": "^1.1.4", "react-mobile-swiper": "^1.1.4",
"react-redux": "^7.0.2", "react-redux": "^7.0.2",
......
import React, {Component} from 'react'
import Routes from './router'
import cookie from 'js-cookie'
// 默认样式
import './assets/css/index.scss';
// iconfont
import './assets/font/iconfont.css';
export default class App extends Component{
componentDidMount(){
//平台信息,后台统计用
cookie.set('plat', '5')
}
render(){
return <Routes/>
}
}
\ No newline at end of file
...@@ -12,7 +12,9 @@ import { compose } from 'redux' ...@@ -12,7 +12,9 @@ import { compose } from 'redux'
class Study extends Component { class Study extends Component {
state = { state = {
position: {
}
} }
list; list;
...@@ -42,11 +44,11 @@ class Study extends Component { ...@@ -42,11 +44,11 @@ class Study extends Component {
<div className="study-container" ref={el => this.list = el}> <div className="study-container" ref={el => this.list = el}>
<Switch> <Switch>
<Redirect exact from='/study' to='study/my-course'/> <Redirect exact from='/study' to='study/my-course'/>
{/*<Route path={`${this.props.match.path}/my-course`} component={MyCourses}/> <Route path={`${this.props.match.path}/my-course`} component={MyCourses}/>
<Route path={`${this.props.match.path}/free-course`} component={FreeCourses}/>*/} <Route path={`${this.props.match.path}/free-course`} component={FreeCourses}/>
<Route path={`${this.props.match.path}/my-course`} render={props => { {/*<Route path={`${this.props.match.path}/my-course`} render={props => {
<MyCourses storeScrollPosition={this.storeScrollPosition}/> <MyCourses storeScrollPosition={this.storeScrollPosition}/>
}}/> }}/>*/}
<Route path={`${this.props.match.path}/free-course`} component={FreeCourses}/> <Route path={`${this.props.match.path}/free-course`} component={FreeCourses}/>
</Switch> </Switch>
</div> </div>
......
...@@ -9,14 +9,14 @@ export const receiveMyCourses = payload => ({ ...@@ -9,14 +9,14 @@ export const receiveMyCourses = payload => ({
const PAGE_INTERVAL = 1 const PAGE_INTERVAL = 1
const NUM_INTERVAL = 10 export const NUM_INTERVAL = 10
export const fetchCoursesListIfNeeded = () => (dispatch, getState) => { export const fetchCoursesListIfNeeded = () => (dispatch, getState) => {
const myCourses = getState().myCourses const myCourses = getState().myCourses
const {shouldFetch, page, num} = myCourses const {shouldFetch, page} = myCourses
if (shouldFetch) { if (shouldFetch) {
dispatch(getMyCourses({ dispatch(getMyCourses({
page: page + PAGE_INTERVAL, page: page + PAGE_INTERVAL,
num: num + NUM_INTERVAL num: NUM_INTERVAL
})) }))
} }
} }
...@@ -24,8 +24,11 @@ export const fetchCoursesListIfNeeded = () => (dispatch, getState) => { ...@@ -24,8 +24,11 @@ export const fetchCoursesListIfNeeded = () => (dispatch, getState) => {
export const getMyCourses = payload => dispatch => { export const getMyCourses = payload => dispatch => {
return api.get(`/m/my_course/${payload.page}/${payload.num}`) return api.get(`/m/my_course/${payload.page}/${payload.num}`)
.then(res => { .then(res => {
const {data,code,msg} = res.data
dispatch(receiveMyCourses({ dispatch(receiveMyCourses({
courseData: res.data, courseList: data,
statusCode: code,
msg: msg,
page: payload.page, page: payload.page,
num: payload.num num: payload.num
})) }))
...@@ -38,3 +41,7 @@ export const invalidateCourseDate = () => ({ ...@@ -38,3 +41,7 @@ export const invalidateCourseDate = () => ({
type: INVALIDATE_COURSEDATA type: INVALIDATE_COURSEDATA
}) })
export const VALIDATE_COURSEDATA = 'VALIDATE_COURSEDATA'
export const validateCourseData = () => ({
type: VALIDATE_COURSEDATA
})
...@@ -3,10 +3,9 @@ import { VList } from '@/common' ...@@ -3,10 +3,9 @@ import { VList } from '@/common'
import './my-courses.scss' import './my-courses.scss'
import { isToday, format } from "date-fns" import { isToday, format } from "date-fns"
import { connect } from "react-redux" import { connect } from "react-redux"
import { fetchCoursesListIfNeeded } from "./actions" import { fetchCoursesListIfNeeded, validateCourseData } from "./actions"
import InfiniteScroll from 'react-infinite-scroller'
import {debounce} from 'lodash'
function getStudyTime(seconds) { function getStudyTime(seconds) {
...@@ -17,13 +16,11 @@ function getStudyTime(seconds) { ...@@ -17,13 +16,11 @@ function getStudyTime(seconds) {
} }
} }
function AddCourse(props) { const AddCourse = React.memo(({addCourseClick}) => (
return ( <div className='add-course'>
<div className='add-course'> <button className='add' onClick={addCourseClick}>添加课程+</button>
<button className='add' onClick={props.addCourseClick}>添加课程+</button> </div>
</div> ))
)
}
function Record({record: {seconds, lesson_name}}) { function Record({record: {seconds, lesson_name}}) {
let re = /第[\s\S]+?课/, let re = /第[\s\S]+?课/,
...@@ -53,16 +50,24 @@ function Record({record: {seconds, lesson_name}}) { ...@@ -53,16 +50,24 @@ function Record({record: {seconds, lesson_name}}) {
} }
const Bottom = React.memo(({item}) => {
if (item.ago || item.seconds) {
let date = new Date(item.ago * 1000)
let time = isToday(date) ? format(date, 'HH时mm分') : format(date, 'MM月DD日')
return (
<div className="des">
<span className='time'>{time}</span>
<Record record={item}/>
</div>
)
}
return (
<button className='start-learn'>开始学习</button>
)
})
class MyCourses extends PureComponent { class MyCourses extends PureComponent {
state = {
addVisible: false,
courseData: []
}
list; list;
handleClick = () => { handleClick = () => {
...@@ -75,45 +80,53 @@ class MyCourses extends PureComponent { ...@@ -75,45 +80,53 @@ class MyCourses extends PureComponent {
componentDidMount() { componentDidMount() {
this.props.fetchCoursesListIfNeeded(); this.props.fetchCoursesListIfNeeded();
} }
componentWillUnmount() { componentDidUpdate() {
console.log('will unmount') console.log('updated')
} }
loadFunc = debounce(() => {
if(this.props.courseList.length % 10 === 0){
this.props.validateCourseData();
this.props.fetchCoursesListIfNeeded();
}
}, 200)
render() { render() {
let {data} = this.props.courseData let list = this.props.courseList
if (data && data.length !== 0) { if (list && list.length !== 0) {
return ( return (
<> <>
<ul ref={el => this.list = el}> <InfiniteScroll
{ pageStart={0}
data.map((item, index) => { hasMore={true}
loadMore={this.loadFunc}
let date = new Date(item.ago * 1000) useWindow={false}
let time = isToday(date) ? format(date, 'HH时mm分') : format(date, 'MM月DD日') >
<ul ref={el => this.list = el}>
const Info = ( {
<div className="info"> list.map((item, index) => {
<p className='title'>{item.course_title}</p>
<p className='contact'>QQ群:{item.course_qq || 449141326}</p> const Info = (
<p className='des'> <div className="info">
<span className='time'>{time}</span> <p className='title'>{item.course_title}</p>
<Record record={item}/> <p className='contact'>QQ群:{item.course_qq || 449141326}</p>
</p> <Bottom item={item}/>
</div> </div>
) )
return ( return (
<VList img={item.image_name} <VList img={item.image_name}
handleClick={this.handleClick} handleClick={this.handleClick}
{...item} {...item}
key={index} key={index}
info={Info}/> info={Info}/>
) )
}) })
} }
</ul> </ul>
</InfiniteScroll>
{ {
this.state.addVisible ? list.length % 10 !== 0 ?
<AddCourse addCourseClick={this.addCourseClick}/> <AddCourse addCourseClick={this.addCourseClick}/>
: null : null
} }
...@@ -135,9 +148,12 @@ class MyCourses extends PureComponent { ...@@ -135,9 +148,12 @@ class MyCourses extends PureComponent {
} }
const mapStateToProps = state => ({ const mapStateToProps = state => ({
courseData: state.myCourses.courseData courseList: state.myCourses.courseList
}) })
const mapDispatchToProps = {fetchCoursesListIfNeeded} const mapDispatchToProps = {
fetchCoursesListIfNeeded,
validateCourseData
}
export default connect(mapStateToProps, mapDispatchToProps)(MyCourses) export default connect(mapStateToProps, mapDispatchToProps)(MyCourses)
\ No newline at end of file
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
.contact { .contact {
font-size: 13px; font-size: 13px;
color: $red; color: $red;
flex: 0 1 auto;
width: 100%;
} }
.des { .des {
...@@ -27,6 +29,20 @@ ...@@ -27,6 +29,20 @@
margin-right: 10px; margin-right: 10px;
} }
} }
.start-learn{
display: block;
box-sizing: border-box;
align-self: flex-end;
width: 78px;
height: 22px;
padding: 5px 14px;
-webkit-appearance: none;
outline: 0;
border: none;
background: $bg_active;
color: $white;
border-radius: 3px;
}
} }
.add-course { .add-course {
......
import { import {
RECEIVE_MY_COURSES, RECEIVE_MY_COURSES,
INVALIDATE_COURSEDATA INVALIDATE_COURSEDATA,
VALIDATE_COURSEDATA
} from './actions' } from './actions'
const initialState = { const initialState = {
shouldFetch: true, shouldFetch: true,
courseData: [], courseList: [],
page: 0, page: 0,
num: 0 statusCode: 0,
msg: '',
noMore: false
} }
export default function myCourses(state = initialState, action) { export default function myCourses(state = initialState, action) {
switch (action.type) { switch (action.type) {
case RECEIVE_MY_COURSES: case RECEIVE_MY_COURSES:
return {...state, ...action.payload} let {courseList, ...rest} = action.payload
return {...state, ...rest, courseList: state.courseList.concat(courseList)}
case INVALIDATE_COURSEDATA: case INVALIDATE_COURSEDATA:
return {...state, shouldFetch: false} return {...state, shouldFetch: false}
case VALIDATE_COURSEDATA:
return {...state, shouldFetch: true}
default: default:
return state return state
} }
......
...@@ -4,15 +4,8 @@ import { createStore, applyMiddleware } from 'redux' ...@@ -4,15 +4,8 @@ import { createStore, applyMiddleware } from 'redux'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import thunk from 'redux-thunk' import thunk from 'redux-thunk'
import logger from 'redux-logger' import logger from 'redux-logger'
import Routes from './router';
import rootReducers from './store' import rootReducers from './store'
import App from './App'
// 默认样式
import './assets/css/index.scss';
// iconfont
import './assets/font/iconfont.css';
const store = createStore( const store = createStore(
rootReducers, rootReducers,
...@@ -22,6 +15,6 @@ const store = createStore( ...@@ -22,6 +15,6 @@ const store = createStore(
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<Routes/> <App/>
</Provider>, </Provider>,
document.getElementById('root')); document.getElementById('root'));
\ No newline at end of file
import axios from "axios"; import axios from "axios";
import qs from 'qs' import qs from 'qs'
export const BASE_URL = process.env.NODE_ENV === 'development' ? '/api': 'https://api.julyedu.com' export const BASE_URL = process.env.NODE_ENV === 'development' ? '/api' : 'https://api.julyedu.com'
const instance = axios.create({ const instance = axios.create({
baseURL: BASE_URL, baseURL: BASE_URL,
transformRequest: [ transformRequest: [
(data) => qs.stringify(data) (data) => qs.stringify(data)
] ],
headers: {
HTTP_PLAT_FORM: 5,
HTTP_PLAT: 5
}
}) })
export default instance export default instance
\ 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