Commit f67e6ca8 by zhanghaozhe

study redux

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