Commit 5305b8d8 by xuzhenghua

Merge branch 'master' of gitlab.julyedu.com:baiguangyao/mr-julyedu into detail

parents 6e0d7efc c3c32002
...@@ -61,6 +61,7 @@ ...@@ -61,6 +61,7 @@
"react-mobile-swiper": "^1.1.4", "react-mobile-swiper": "^1.1.4",
"react-redux": "^7.0.2", "react-redux": "^7.0.2",
"react-router-dom": "^5.0.1", "react-router-dom": "^5.0.1",
"react-spinners": "^0.5.4",
"redux": "^4.0.1", "redux": "^4.0.1",
"redux-immutable": "^4.0.0", "redux-immutable": "^4.0.0",
"redux-logger": "^3.0.6", "redux-logger": "^3.0.6",
......
import React, { Component } from 'react' import React, { Component } from 'react'
import Routes from './router' import Routes from './router'
import cookie from 'js-cookie' import cookie from 'js-cookie'
import { http, api } from '@/utils'; import { connect } from "react-redux";
import { connect } from 'react-redux'; import { setCurrentUser, startFetchUser } from "@/store/userAction";
import { setCurrentUser } from '@/store/userAction'; import { withRouter } from 'react-router-dom'
import { compose } from 'redux'
import { api, getParam, http } from "@/utils";
import { Toast } from "antd-mobile";
import jsCookie from 'js-cookie'
import { addDays } from 'date-fns'
//拦截ajax请求,返回mock数据 //拦截ajax请求,返回mock数据
...@@ -24,12 +29,45 @@ class App extends Component { ...@@ -24,12 +29,45 @@ class App extends Component {
//平台信息 //平台信息
cookie.set('plat', '5') cookie.set('plat', '5')
this.props.startFetchUser()
http.get(`${api.home}/m/user_info`).then(res => { http.get(`${api.home}/m/user_info`).then(res => {
this.props.setCurrentUser(this.storeUser(res)) this.props.setCurrentUser(this.transformUser(res))
}) })
let code = getParam('code')
if (code) {
http.get(`${api['home']}/m/wx_loginInfo/code/${code}`)
.then(res => {
let data = res.data
console.log(res)
if (data.errno == 200) {
if (data.data['is_bind_mobile']) {
window.location.assign(data.data.url)
} else {
let user = this.transformWxUser(res)
let {role, uid, token} = data.data
let expires = {expires: addDays(new Date(), 90)}
jsCookie.set('role', role, expires)
jsCookie.set('uid', uid, expires)
jsCookie.set('token', token, expires)
this.props.receiveUser(user)
}
} else {
Toast.info(data.msg)
}
})
}
} }
storeUser = res => { transformUser = res => {
let payload let payload
if (res.data.code === 200) { if (res.data.code === 200) {
const { const {
...@@ -64,13 +102,41 @@ class App extends Component { ...@@ -64,13 +102,41 @@ class App extends Component {
return payload return payload
} }
transformWxUser = res => {
let data = res.data
if (data.errno == 200) {
let {uid, token, avatar_file: avatar, uname: username,} = data.data
return {
hasError: false,
data: {
uid,
token,
avatar,
username
},
msg: data.msg
}
} else {
let {code, msg} = data.data
return {
code,
msg,
hasError: true,
data: {}
}
}
}
render() { render() {
return <Routes/> return <Routes/>
} }
} }
export default connect( export default compose(
null, connect(
{setCurrentUser} null,
{setCurrentUser, startFetchUser}
),
withRouter
)(App) )(App)
\ No newline at end of file
import React, { Component } from 'react' import React, { Component } from 'react';
import { ActivityIndicator } from 'antd-mobile' import ReactDOM from 'react-dom'
import { HashLoader } from "react-spinners";
import './loading.scss' import './loading.scss'
export default class componentName extends Component {
const container = document.body
class Loading extends Component {
static defaultProps = {
text: '加载中',
fake: 0
}
state = {
isLoading: true
}
componentDidUpdate(prevProps) {
let {isLoading, fake} = this.props
if (!isLoading) {
if(fake){
setTimeout(() => {
this.setState({
isLoading
})
}, fake)
}else {
if(prevProps.isLoading != isLoading){
this.setState({
isLoading
})
}
}
}
}
render() { render() {
return ( const innerLoading =
<div className="loading"> <div className="loading">
<ActivityIndicator></ActivityIndicator> <div className="loading-wrapper">
<span>加载中</span> <HashLoader
css={{
display: 'block',
marginTop: '-100px'
}}
size={50}
color={'#09f'}
/>
<p>{this.props.text}</p>
</div>
</div> </div>
)
return (
this.state.isLoading ? ReactDOM.createPortal(innerLoading, container) : this.props.children
);
} }
} }
export default Loading;
\ No newline at end of file
.loading{ .loading {
display: flex; position: absolute;
width:100%; top: 50%;
height:44px; left: 50%;
line-height: 44px; transform: translate(-50%, -50%);
justify-content: center; .loading-wrapper {
align-items: center; display: flex;
span{ flex-flow: column;
margin-left:5px; justify-content: center;
align-items: center;
p {
font-size: 14px;
margin-top: 12px;
color: $active;
}
} }
} }
\ No newline at end of file
...@@ -6,6 +6,7 @@ import { compose } from 'redux'; ...@@ -6,6 +6,7 @@ import { compose } from 'redux';
import { accountLogin } from '@/store/userAction'; import { accountLogin } from '@/store/userAction';
import { connect } from "react-redux"; import { connect } from "react-redux";
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { HeaderBar } from "@/common";
import Header from "../common/Header"; import Header from "../common/Header";
...@@ -16,11 +17,6 @@ import { Toast } from "antd-mobile"; ...@@ -16,11 +17,6 @@ import { Toast } from "antd-mobile";
class AccountLogin extends PureComponent { class AccountLogin extends PureComponent {
componentDidMount() {
console.log(this.props.values);
}
render() { render() {
const { const {
errors, errors,
...@@ -28,6 +24,7 @@ class AccountLogin extends PureComponent { ...@@ -28,6 +24,7 @@ class AccountLogin extends PureComponent {
} = this.props } = this.props
return ( return (
<div className={'account-login'}> <div className={'account-login'}>
<HeaderBar arrow={true} title={'登录'}/>
<Header/> <Header/>
<Form className="login-info"> <Form className="login-info">
<FastField <FastField
...@@ -75,10 +72,9 @@ const formikConfig = { ...@@ -75,10 +72,9 @@ const formikConfig = {
props.accountLogin({ props.accountLogin({
username, password username, password
}).then(res => { }).then(res => {
console.log(res);
if (!res.hasError) { if (!res.hasError) {
let {from} = props.location.state || {from: {pathname: '/'}} let {from} = props.location.state || {from: {pathname: '/'}}
history.push(from.pathname) history.replace(from.pathname)
} else { } else {
Toast.info(res.msg, 2, null, false) Toast.info(res.msg, 2, null, false)
} }
......
...@@ -11,13 +11,6 @@ ...@@ -11,13 +11,6 @@
margin-bottom: 21px; margin-bottom: 21px;
} }
.place {
width: 100%;
height: 39px;
margin-bottom: 33px;
background: #56abff;
}
.verification { .verification {
margin-bottom: 21px; margin-bottom: 21px;
} }
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import './binding-tel.scss' import './binding-tel.scss'
import { withFormik, Field, Form } from "formik";
import { validateTel, http, api, getParam } from "@/utils";
import { compose } from "redux";
import { connect } from "react-redux";
import { setCurrentUser } from "@/store/userAction";
import Captcha from '@/common/Captcha'
import ClearableInput from '@common/ClearableInput' import ClearableInput from '@common/ClearableInput'
import Button from '../common/Button' import Button from '../common/Button'
import VeriCodeInput from '../common/veriCodeInput' import VeriCodeInput from '../common/veriCodeInput'
import { Toast } from "antd-mobile";
import { isEmpty } from "lodash";
class BindingTel extends Component { class BindingTel extends Component {
constructor(props) {
super(props); state = {
this.state = { validate: null,
veriCode: '' captchaInstance: null
};
} }
handleChange = (val) => { getCaptchaInstance = instance => {
this.setState({veriCode: val}); this.setState({
captchaInstance: instance
})
}
onVerify = (err, data) => {
if (err) {
console.log(err)
} else {
this.setState({
validate: data.validate
})
}
} }
render() { render() {
const {
values,
errors
} = this.props
return ( return (
<div className={'binding-tel'}> <div className={'binding-tel'}>
<p className={'title'}>为提高您的账号安全,请绑定手机号</p> <p className={'title'}>为提高您的账号安全,请绑定手机号</p>
<ClearableInput <Form>
type={'number'} <Field
placeholder={'请输入需要绑定的手机号'} name='tel'
wrapperClass={'tel'} render={({field, form}) => {
icon={<i className={'iconfont iconshouji'} return (
style={{fontSize: '22px', left: '11px'}} <ClearableInput
/>} {...field}
/> setFieldValue={form.setFieldValue}
<VeriCodeInput placeholder={'请输入需要绑定的手机号'}
type={'number'} wrapperClass={'tel'}
className={'verification'} icon={<i className={'iconfont iconshouji'}
onChange={this.handleChange} style={{fontSize: '22px', left: '11px'}}
icon={<i className={'iconfont iconduanxin'} />}
style={{fontSize: '20px', left: '12px'}} />
/>}
/> )
<div className="place"/> }}
<Button className={'complete-btn'}>完成</Button> />
<Field
name='veriCode'
render={({field}) => {
return (
<VeriCodeInput
{...field}
className={'verification'}
icon={<i className={'iconfont iconduanxin'}
style={{fontSize: '20px', left: '12px'}}
/>}
account={values.tel}
tel={values.tel}
challenge={this.state.validate}
instance={this.state.captchaInstance}
action={'auth'}
/>
)
}}
/>
<Captcha onVerify={this.onVerify} getInstance={this.getCaptchaInstance}/>
<Button className={'complete-btn'} active={values.tel && values.veriCode && isEmpty(errors)}>完成</Button>
</Form>
</div> </div>
); );
} }
} }
export default BindingTel;
\ No newline at end of file const formikConfig = {
mapPropsToValues() {
return {
tel: '',
veriCode: ''
}
},
validateOnChange: true,
validate(values) {
let errors = {}
if (!validateTel(values.tel)) {
errors.tel = '请输入正确的手机号'
}
if (!values.veriCode) {
errors.veriCode = '请填写验证码'
}
return errors
},
handleSubmit(values, {props}) {
http.post(`${api['passport-api']}/bind_mobile`, {
phone_num: values.tel,
phone_code: values.veriCode,
mkey: getParam('mkey'),
plat: 5
}).then(res => {
const data = res.data
if (data.errno == 200) {
if (data.data['is_set_pwd']) {
props.setCurrentUser({
hasError: false,
data: {
uid: data.data.uid
},
msg: data.data.msg
})
props.history.replace(`/passport/set-password`)
}else {
location.assign(data.data['jump_url'])
}
} else {
Toast.info(data.msg, 2, null, false)
}
/*props.setCurrentUser({
hasError,
data
})*/
})
}
}
export default compose(
connect(
null,
{setCurrentUser}
),
withFormik(formikConfig),
)(BindingTel);
\ No newline at end of file
import React, { PureComponent } from 'react'; import React, { PureComponent } from 'react';
import { browser } from "@/utils";
import './loginWays.scss' import './loginWays.scss'
class LoginWays extends PureComponent { class LoginWays extends PureComponent {
handleClick = (index) => { state = {
this.props.onClick(index) ways: this.props.loginWays
}
componentDidMount() {
if (!browser.isWeixin) {
this.setState({
ways: this.state.ways.filter(item => item.text !== '微信')
})
}
}
handleClick = text => {
this.props.onClick(text)
} }
render() { render() {
...@@ -14,9 +28,9 @@ class LoginWays extends PureComponent { ...@@ -14,9 +28,9 @@ class LoginWays extends PureComponent {
<div className="bottom-title">其他登录方式</div> <div className="bottom-title">其他登录方式</div>
<ul className='login-ways-container'> <ul className='login-ways-container'>
{ {
this.props.loginWays.map((item, index) => { this.state.ways.map((item, index) => {
return ( return (
<li key={index} onClick={this.handleClick.bind(this, index)}> <li key={index} onClick={this.handleClick.bind(this, item.text)}>
<img src={item.logo} alt=""/> <img src={item.logo} alt=""/>
<p>{item.text}</p> <p>{item.text}</p>
</li> </li>
......
...@@ -36,6 +36,10 @@ ...@@ -36,6 +36,10 @@
li { li {
text-align: center; text-align: center;
a{
display: block;
}
img { img {
width: 34px; width: 34px;
} }
......
...@@ -110,7 +110,7 @@ class VeriCodeInput extends Component { ...@@ -110,7 +110,7 @@ class VeriCodeInput extends Component {
if (!tel) { if (!tel) {
content = '手机号码不能为空' content = '手机号码不能为空'
} }
if (validateTel(tel)) { if (!validateTel(tel)) {
content = '请输入正确格式的手机号码' content = '请输入正确格式的手机号码'
} }
} else { } else {
......
...@@ -128,7 +128,7 @@ const formikConfig = { ...@@ -128,7 +128,7 @@ const formikConfig = {
code: values.veriCode code: values.veriCode
}).then(res => { }).then(res => {
if (res.data.errno == 0) { if (res.data.errno == 0) {
props.history.push('/passport/set-password') props.history.push('/passport/set-password', {from: props.location})
} else { } else {
Toast.info(res.data.msg) Toast.info(res.data.msg)
} }
......
...@@ -8,6 +8,8 @@ import AccountLogin from './accountLogin' ...@@ -8,6 +8,8 @@ import AccountLogin from './accountLogin'
import ForgotPassword from './forgotPassword' import ForgotPassword from './forgotPassword'
import SetPassword from './setPassword' import SetPassword from './setPassword'
import BindingTel from './bindingTel' import BindingTel from './bindingTel'
import {connect} from "react-redux";
import {compose} from "redux";
import account from './account.png' import account from './account.png'
import qq from './qq.png' import qq from './qq.png'
...@@ -17,6 +19,8 @@ import wechat from './wechat.png' ...@@ -17,6 +19,8 @@ import wechat from './wechat.png'
class Passport extends Component { class Passport extends Component {
redirect_url = location.protocol + '//' + location.hostname
constructor(props) { constructor(props) {
super(props); super(props);
...@@ -28,15 +32,18 @@ class Passport extends Component { ...@@ -28,15 +32,18 @@ class Passport extends Component {
}, },
{ {
logo: wechat, logo: wechat,
text: '微信' text: '微信',
url: 'https://www.baidu.com'
}, },
{ {
logo: qq, logo: qq,
text: 'QQ' text: 'QQ',
url: 'https://www.baidu.com'
}, },
{ {
logo: sina, logo: sina,
text: '新浪' text: '新浪',
url: `http://passport-test.julyedu.com/mob/sinalogin?redirect_url=${this.redirect_url}`
}, },
] ]
} }
...@@ -52,7 +59,9 @@ class Passport extends Component { ...@@ -52,7 +59,9 @@ class Passport extends Component {
to={{...location, ...{pathname: '/passport/login'}}} to={{...location, ...{pathname: '/passport/login'}}}
/> />
<Route path={match.url + '/login'} <Route path={match.url + '/login'}
render={props => <Login {...props} loginWays={this.state.loginWays}/>}/> render={props => {
return <Login {...props} loginWays={this.state.loginWays}/>
}}/>
<Route path={match.url + '/account-login'} component={AccountLogin}/> <Route path={match.url + '/account-login'} component={AccountLogin}/>
<Route path={match.url + '/forgot-password'} component={ForgotPassword}/> <Route path={match.url + '/forgot-password'} component={ForgotPassword}/>
<Route path={match.url + '/set-password'} component={SetPassword}/> <Route path={match.url + '/set-password'} component={SetPassword}/>
...@@ -64,4 +73,10 @@ class Passport extends Component { ...@@ -64,4 +73,10 @@ class Passport extends Component {
} }
export default WithFullSize(Passport) export default compose(
\ No newline at end of file connect(
state => ({user: state.user}),
null
),
WithFullSize
)(Passport)
\ No newline at end of file
...@@ -12,21 +12,36 @@ import { connect } from 'react-redux'; ...@@ -12,21 +12,36 @@ import { connect } from 'react-redux';
import { compose } from 'redux'; import { compose } from 'redux';
import { isEmpty } from 'lodash' import { isEmpty } from 'lodash'
import { Toast } from 'antd-mobile'; import { Toast } from 'antd-mobile';
import {validateTel} from "@/utils"; import { validateTel } from "@/utils";
class WechatLogin extends Component { class Login extends Component {
state = { state = {
validate: null, validate: null,
captchaInstance: null captchaInstance: null
} }
loginWaysClick = index => { loginWaysClick = method => {
switch (index) { const {history, loginWays, location} = this.props
case 0:
this.props.history.push('/passport/account-login') const item = loginWays.find(item => item.text === method)
switch (method) {
case '账号登录':
history.push('/passport/account-login', location.state)
break;
case '微信':
let {from} = location.state || {from: {pathname: '/'}}
const redirectURI = window.location.protocol + '//' + window.location.hostname + 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`)
break; break;
default:
window.location.assign(item.url)
} }
} }
getCaptchaInstance = instance => { getCaptchaInstance = instance => {
...@@ -140,4 +155,4 @@ export default compose( ...@@ -140,4 +155,4 @@ export default compose(
{quickLogin} {quickLogin}
), ),
withFormik(FormikConfig), withFormik(FormikConfig),
)(WechatLogin) )(Login)
\ No newline at end of file \ No newline at end of file
...@@ -10,11 +10,15 @@ import { http, api } from "@/utils"; ...@@ -10,11 +10,15 @@ import { http, api } from "@/utils";
import { Toast } from "antd-mobile"; import { Toast } from "antd-mobile";
import { encrypt } from "@/components/passport/encryption"; import { encrypt } from "@/components/passport/encryption";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { isEmpty } from "lodash";
import { connect } from "react-redux";
class SetPassword extends Component { class SetPassword extends Component {
render() { render() {
let {values, errors, location} = this.props
let {from} = location.state || {from: {pathname: '/'}}
return ( return (
<> <>
<HeaderBar arrow={true} title={'设置密码'}/> <HeaderBar arrow={true} title={'设置密码'}/>
...@@ -34,7 +38,8 @@ class SetPassword extends Component { ...@@ -34,7 +38,8 @@ class SetPassword extends Component {
) )
}} }}
/> />
<Button className={'btn-active'}>完成</Button> <Button className={'btn-active'}
active={values.password && values.agreement && isEmpty(errors)}>完成</Button>
<label htmlFor="agreement" className='user-agreement'> <label htmlFor="agreement" className='user-agreement'>
<Field type='checkbox' <Field type='checkbox'
name='agreement' name='agreement'
...@@ -46,7 +51,8 @@ class SetPassword extends Component { ...@@ -46,7 +51,8 @@ class SetPassword extends Component {
同意<span>《七月在线用户使用协议》</span> 同意<span>《七月在线用户使用协议》</span>
</label> </label>
</Form> </Form>
<div className="skip"> <div className="skip"
style={{display: from && from.pathname.includes('forgot-password') ? 'none' : 'block'}}>
<Link replace to='/passport/account-login'>跳过</Link> <Link replace to='/passport/account-login'>跳过</Link>
</div> </div>
</div> </div>
...@@ -64,28 +70,16 @@ const formikConfig = { ...@@ -64,28 +70,16 @@ const formikConfig = {
}, },
handleSubmit: (values, {props}) => { handleSubmit: (values, {props}) => {
let key = sessionStorage.getItem('r_type') === 'email' ? 'email' : 'tel' let {from} = props.location.state || {from: {pathname: '/'}}
let encrypted = encrypt(values.password) if (from.pathname.includes('forgot-password')) {
forgotPasswordReset(values, props);
http.post(`${api['passport-api']}/up_pass${key === 'tel' && '_by_phone' || ''}`, { } else {
[key]: sessionStorage.getItem(key), bindMobileSetPassword(values, props)
pass: encrypted, }
re_pass: encrypted
})
.then(res => {
if (res.data.errno == 0) {
Toast.info('密码设置成功')
setTimeout(function () {
props.history.replace('/passport')
}, 1000)
} else {
Toast.info(res.data.msg, 2, null, false)
}
})
}, },
validateOnChange: false, validateOnChange: false,
validate: (values) => { validate: values => {
let errors = {} let errors = {}
const re = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/; const re = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/;
if (!re.test(values.password)) { if (!re.test(values.password)) {
...@@ -100,6 +94,49 @@ const formikConfig = { ...@@ -100,6 +94,49 @@ const formikConfig = {
} }
} }
function forgotPasswordReset(values, props) {
let key = sessionStorage.getItem('r_type') === 'email' ? 'email' : 'tel'
http.post(`${api['passport-api']}/account/up_pass_by_${key === 'email' ? 'email' : 'phone'}`, {
[key]: sessionStorage.getItem(key),
password: encrypt(values.password)
})
.then(res => {
if (res.data.errno == 200) {
Toast.info('密码设置成功')
setTimeout(function () {
props.history.replace('/passport/account-login')
}, 1000)
} else {
Toast.info(res.data.msg, 2, null, false)
}
})
}
function bindMobileSetPassword(values, props) {
http.post(`${api['passport-api']}/bind_mobile/set_pwd_new`, {
uid: props.user.data.uid,
password: encrypt(values.password)
})
.then(res => {
if (res.data.errno == 200) {
Toast.info('密码设置成功')
let {from} = location.state || {from: {pathname: '/'}}
setTimeout(function () {
props.history.replace(from.pathname)
}, 1000)
} else {
Toast.info(res.data.msg, 2, null, false)
}
})
}
export default compose( export default compose(
connect(
state => ({user: state.user}),
null
),
withFormik(formikConfig) withFormik(formikConfig)
)(SetPassword); )(SetPassword);
\ No newline at end of file
...@@ -4,6 +4,7 @@ import Tag from '@common/Tag/index.js' ...@@ -4,6 +4,7 @@ import Tag from '@common/Tag/index.js'
import { http, api } from '@/utils' import { http, api } from '@/utils'
import './index.scss'; import './index.scss';
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import Loading from '@/common/Loading'
class Search extends PureComponent { class Search extends PureComponent {
...@@ -12,14 +13,16 @@ class Search extends PureComponent { ...@@ -12,14 +13,16 @@ class Search extends PureComponent {
searchHistory: JSON.parse(localStorage.getItem('searchHistory')) || [], searchHistory: JSON.parse(localStorage.getItem('searchHistory')) || [],
hot_words: [], hot_words: [],
searchList: [], searchList: [],
value: '' value: '',
isLoading: true
} }
async componentDidMount() { async componentDidMount() {
const res = await http.get(`${api['search-api']}/search_hot_word`) const res = await http.get(`${api['search-api']}/search_hot_word`)
if (res.data.errno === 0) { if (res.data.errno === 0) {
this.setState({ this.setState({
hot_words: res.data.data.info.hot_words hot_words: res.data.data.info.hot_words,
isLoading: false
}) })
} }
} }
...@@ -54,51 +57,53 @@ class Search extends PureComponent { ...@@ -54,51 +57,53 @@ class Search extends PureComponent {
handleChange={this.handleChange} handleChange={this.handleChange}
handleSearch={this.handleSearch} handleSearch={this.handleSearch}
/> />
<div className="search-main"> <Loading isLoading={this.state.isLoading}>
<div className="search-land"> <div className="search-main">
<div className='search-history'> <div className="search-land">
<span>最近搜索</span> <div className='search-history'>
<i className="iconfont iconiconfront-56" onClick={this.clearHistory}/> <span>最近搜索</span>
<i className="iconfont iconiconfront-56" onClick={this.clearHistory}/>
</div>
<div className="search-tag">
{
searchHistory.length > 0 ?
searchHistory.map((v, i) => {
return (
<Link
key={i}
to={`/search-result?word=${encodeURIComponent(v)}`}
>
<Tag>{v}</Tag>
</Link>
)
})
: <div style={{textAlign: 'center', padding: '20px'}}>暂无历史</div>
}
</div>
</div> </div>
<div className="search-tag"> <div className="search-land search-hot">
{ <label>
searchHistory.length > 0 ? <span>热门搜索</span>
searchHistory.map((v, i) => { </label>
return ( <div className="search-tag">
<Link {
key={i} this.state['hot_words'].length > 0 ?
to={`/search-result?word=${encodeURIComponent(v)}`} this.state['hot_words'].map((v, i) => {
> return (
<Tag>{v}</Tag> <Link key={i}
</Link> to={`/search-result?word=${encodeURIComponent(v)}`}
) onClick={this.storeHistory.bind(this, v)}
}) >
: <div style={{textAlign: 'center', padding: '20px'}}>暂无历史</div> <Tag>{v}</Tag>
} </Link>
)
})
: <div style={{textAlign: 'center', padding: '20px'}}>暂无热门</div>
}
</div>
</div> </div>
</div> </div>
<div className="search-land search-hot"> </Loading>
<label>
<span>热门搜索</span>
</label>
<div className="search-tag">
{
this.state['hot_words'].length > 0 ?
this.state['hot_words'].map((v, i) => {
return (
<Link key={i}
to={`/search-result?word=${encodeURIComponent(v)}`}
onClick={this.storeHistory.bind(this, v)}
>
<Tag>{v}</Tag>
</Link>
)
})
: <div style={{textAlign: 'center', padding: '20px'}}>暂无热门</div>
}
</div>
</div>
</div>
</div> </div>
) )
......
...@@ -2,6 +2,7 @@ import React from 'react'; ...@@ -2,6 +2,7 @@ import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose } from 'redux' import { createStore, applyMiddleware, compose } from 'redux'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { BrowserRouter as Router } from 'react-router-dom'
import thunk from 'redux-thunk' import thunk from 'redux-thunk'
import logger from 'redux-logger' import logger from 'redux-logger'
import rootReducers from './store' import rootReducers from './store'
...@@ -20,6 +21,8 @@ const store = createStore( ...@@ -20,6 +21,8 @@ const store = createStore(
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>
<App/> <Router>
<App/>
</Router>
</Provider>, </Provider>,
document.getElementById('root')); document.getElementById('root'));
\ No newline at end of file
import React from 'react' import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom' import { Switch, Route } from 'react-router-dom'
import RouterConfig from './router-config' import RouterConfig from './router-config'
import PrivateRoute from './privateRoute' import PrivateRoute from './privateRoute'
export default function () { export default function () {
return ( return (
<Router> <Switch>
<Switch> {RouterConfig.map((item, index) => {
{RouterConfig.map((item, index) => { let {isPrivate, ...rest} = item
let {isPrivate, ...rest} = item if (isPrivate) {
if (isPrivate) { return <PrivateRoute {...rest} key={index}/>
return <PrivateRoute {...rest} key={index}/> } else {
} else { return (
return ( <Route {...rest} key={index}/>
<Route {...rest} key={index}/> )
) }
} })}
})} </Switch>
</Switch>
</Router>
) )
} }
\ No newline at end of file
import React from 'react'; import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { withRouter } from "react-router-dom"; import { withRouter } from "react-router-dom";
import { compose } from "redux"; import { compose } from "redux";
import { connect } from "react-redux";
const Loading = ({user, history, state}) => { function Loading(props) {
if (Object.values(user.data).filter(item => !!item).length !== 0) {
history.replace(location.pathname) useEffect(() => {
} else { let {user, location, history} = props
history.replace('/passport', {...state}) if (!user.isFetching) {
} if (user.hasError) {
history.push('/passport', {from: location})
} else {
if (Object.values(user.data).every(item => !!item).length !== 0) {
history.push(location.pathname)
}
}
}
})
return ( return (
<div className={'loading'}> <div className={'loading'}>
loading... loading...
</div> </div>
); );
}; }
export default compose( export default compose(
connect( connect(
...@@ -23,4 +32,4 @@ export default compose( ...@@ -23,4 +32,4 @@ export default compose(
null null
), ),
withRouter withRouter
)(Loading); )(Loading)
\ No newline at end of file \ No newline at end of file
import React from 'react'; import React from 'react';
import { Route, Redirect } from "react-router-dom"; import { Route } from "react-router-dom";
import { connect } from "react-redux"; import { connect } from "react-redux";
import jsCookie from 'js-cookie' import jsCookie from 'js-cookie'
import Loading from './loading' import Loading from './loading'
const PrivateRoute = ({component: Component, path, user, ...rest}) => { const PrivateRoute = ({component: Component, path, user, ...rest}) => {
let authenticated = jsCookie.get('token') && jsCookie.get('uid') let authenticated = jsCookie.get('token') && jsCookie.get('uid')
return ( return (
<Route {...rest} render={props => { <Route {...rest} render={props => {
return authenticated return authenticated
......
...@@ -16,9 +16,10 @@ import Examination from '@/components/examination' ...@@ -16,9 +16,10 @@ import Examination from '@/components/examination'
import ShopCart from '@/components/shopCart'; import ShopCart from '@/components/shopCart';
import BargainMiddlePage from '@/components/bargainMiddlePage'; import BargainMiddlePage from '@/components/bargainMiddlePage';
import Passport from '@/components/passport'; import Passport from '@/components/passport';
import {Scholarship} from '@/components/scholarship/index'; import { Scholarship } from '@/components/scholarship/index';
import DrawDocument from '@/components/scholarship/DrawDocument/DrawDocument'; import DrawDocument from '@/components/scholarship/DrawDocument/DrawDocument';
import PayOrder from '@/components/order/payOrder/PayOrder' import PayOrder from '@/components/order/payOrder/PayOrder'
import Loading from '@/common/Loading'
const Coupons = loadable(() => import(/* webpackChunkName: 'coupons'*/ '@/components/coupons')) const Coupons = loadable(() => import(/* webpackChunkName: 'coupons'*/ '@/components/coupons'))
const Study = loadable(() => import(/* webpackChunkName: 'study'*/'@/components/study')) const Study = loadable(() => import(/* webpackChunkName: 'study'*/'@/components/study'))
...@@ -137,5 +138,9 @@ export default [ ...@@ -137,5 +138,9 @@ export default [
component: ToGroup, component: ToGroup,
isPrivate: true isPrivate: true
}, },
{
path: '/loading',
component: Loading,
},
] ]
\ No newline at end of file
...@@ -12,7 +12,7 @@ module.exports = function (app) { ...@@ -12,7 +12,7 @@ module.exports = function (app) {
pathRewrite: { pathRewrite: {
[`^${config[item]['development']}`]: '' [`^${config[item]['development']}`]: ''
}, },
cookieDomainRewrite: 'localhost', // cookieDomainRewrite: 'localhost',
...config[item]['proxy'] ...config[item]['proxy']
} }
)) ))
......
...@@ -45,7 +45,7 @@ const storeUser = (res, dispatch) => { ...@@ -45,7 +45,7 @@ const storeUser = (res, dispatch) => {
const SET_CURRENT_USER = 'SET_CURRENT_USER' const SET_CURRENT_USER = 'SET_CURRENT_USER'
const setCurrentUser = payload => ({ const setCurrentUser = payload => ({
type: SET_CURRENT_USER, type: SET_CURRENT_USER,
payload payload: {...payload, isFetching: false}
}) })
...@@ -63,6 +63,12 @@ const updateUser = payload => ({ ...@@ -63,6 +63,12 @@ const updateUser = payload => ({
payload payload
}) })
const START_FETCH_USER = 'START_FETCH_USER'
const startFetchUser = () => ({
type: START_FETCH_USER
})
export { export {
accountLogin, accountLogin,
SET_CURRENT_USER, SET_CURRENT_USER,
...@@ -70,5 +76,7 @@ export { ...@@ -70,5 +76,7 @@ export {
quickLogin, quickLogin,
logout, logout,
UPDATE_USER, UPDATE_USER,
updateUser updateUser,
START_FETCH_USER,
startFetchUser,
} }
\ No newline at end of file
import { SET_CURRENT_USER, UPDATE_USER } from '@/store/userAction'; import { SET_CURRENT_USER, UPDATE_USER, START_FETCH_USER } from '@/store/userAction';
import { merge } from 'lodash' import { merge } from 'lodash'
...@@ -12,7 +12,8 @@ const initialState = { ...@@ -12,7 +12,8 @@ const initialState = {
token: '', token: '',
email: '', email: '',
uid: '' uid: ''
} },
isFetching: true
} }
...@@ -22,6 +23,8 @@ export default function (state = initialState, action) { ...@@ -22,6 +23,8 @@ export default function (state = initialState, action) {
return action.payload return action.payload
case UPDATE_USER: case UPDATE_USER:
return merge({}, state, action.payload) return merge({}, state, action.payload)
case START_FETCH_USER:
return {...state, isFetching: true}
default: default:
return state return state
} }
......
export { default as http } from './http' import jsCookie from "js-cookie";
export { default as api } from './api'
export { html, initCaptcha, validateTel, validateEmail,browser }
export const getParam = (key, str) => { export const getParam = (key, str) => {
...@@ -87,4 +85,13 @@ const browser = (function () { ...@@ -87,4 +85,13 @@ const browser = (function () {
isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua), isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua),
isIPad: /iPad/i.test(ua) isIPad: /iPad/i.test(ua)
} }
})() })()
\ No newline at end of file
const isLogin = (function () {
return jsCookie.get('uid') && jsCookie.get('token')
})()
export { default as http } from './http'
export { default as api } from './api'
export { html, initCaptcha, validateTel, validateEmail, browser, isLogin }
const config = { const config = {
home: { home: {
development: '/api', development: '/api',
test: 'http://fast-test.julyedu.com', test: 'http://fast-test.julyedu.com',
...@@ -25,11 +25,19 @@ const config = { ...@@ -25,11 +25,19 @@ const config = {
production: 'http://passport.julyedu.com', production: 'http://passport.julyedu.com',
proxy: {} proxy: {}
}, },
'pay-api':{ 'pay-api': {
development: '/pay-api', development: '/pay-api',
test: 'http://api-test.julyedu.com', test: 'http://api-test.julyedu.com',
production: 'https://api.julyedu.com', production: 'https://api.julyedu.com',
proxy: {} proxy: {}
},
'base-api': {
development: '/base-api',
test: 'http://api-test.julyedu.com',
production: 'https://api.julyedu.com',
proxy: {
secure: false
}
} }
} }
......
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