Commit 2d6e62de by xuzhenghua

test

parent 8797b9e8
......@@ -3692,6 +3692,11 @@
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk="
},
"clipboard-copy": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/clipboard-copy/-/clipboard-copy-3.1.0.tgz",
"integrity": "sha512-Xsu1NddBXB89IUauda5BIq3Zq73UWkjkaQlPQbLNvNsd5WBMnTWPNKYR6HGaySOxGYZ+BKxP2E9X4ElnI3yiPA=="
},
"cliui": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz",
......@@ -3984,14 +3989,6 @@
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40="
},
"copy-to-clipboard": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.2.0.tgz",
"integrity": "sha512-eOZERzvCmxS8HWzugj4Uxl8OJxa7T2k1Gi0X5qavwydHIfuSHq2dTD09LOg/XyGq4Zpb5IsR/2OJ5lbOegz78w==",
"requires": {
"toggle-selection": "^1.0.6"
}
},
"core-js": {
"version": "2.6.5",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
......@@ -12087,15 +12084,6 @@
}
}
},
"react-copy-to-clipboard": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz",
"integrity": "sha512-ELKq31/E3zjFs5rDWNCfFL4NvNFQvGRoJdAKReD/rUPA+xxiLPQmZBZBvy2vgH7V0GE9isIQpT9WXbwIVErYdA==",
"requires": {
"copy-to-clipboard": "^3",
"prop-types": "^15.5.8"
}
},
"react-dev-utils": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-8.0.0.tgz",
......@@ -14514,11 +14502,6 @@
"repeat-string": "^1.6.1"
}
},
"toggle-selection": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
"integrity": "sha1-bkWxJj8gF/oKzH2J14sVuL932jI="
},
"topo": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/topo/-/topo-2.0.2.tgz",
......
......@@ -37,6 +37,10 @@ class App extends Component {
...this.props.location
}
records = []
firstLoad = true
componentDidMount() {
// 友盟统计
const script = document.createElement('script');
......@@ -44,7 +48,7 @@ class App extends Component {
script.language = 'JavaScript';
document.body.appendChild(script);
this.setNavigationRecord(this.props.location)
this.setNavigationRecord(this.props.location, this.props.history.action)
//平台信息
......@@ -58,9 +62,10 @@ class App extends Component {
this.utm()
const routeMatchRule = /binding-tel|forgot|set-password/
const {history} = this.props
history.listen((location) => {
history.listen((location, action) => {
this.firstLoad = false
this.setNavigationRecord(location, action)
this.utm()
this.setNavigationRecord(location)
if (cookie.get('uid') && this.props.user.hasError) {
this.getUser()
}
......@@ -69,7 +74,7 @@ class App extends Component {
if (routeMatchRule.test(pathname)) {
return
}
location.state = {from: this.previousLocation};
location.state = {...location.state, ...{from: this.previousLocation}};
} else {
this.removeShareCodeCookie()
}
......@@ -82,17 +87,23 @@ class App extends Component {
cookie.remove('share_code', {path: '/', domain: '.julyedu.com'})
}
setNavigationRecord = (location) => {
let {location: _location} = this.props
let {state: _state = {}} = _location
let {state = {}} = location
location.state = {
...state, ...{
record: _state.record ?
[..._state.record, {pathname: location.pathname, search: location.search, hash: location.hash}] :
[{pathname: location.pathname, search: '', hash: ''}]
}
setNavigationRecord = (location, action) => {
const {pathname, search, hash} = location
let isLastRecord = location.pathname === this.records.length && this.records[this.records.length - 1].pathname
switch (action) {
case 'POP':
this.firstLoad ? this.records.push({pathname, search, hash}) : this.records.pop()
break
case 'REPLACE':
this.records[this.records.length - 1] = {pathname, search, hash}
break
default:
!isLastRecord && this.records.push({pathname, search, hash})
}
location.state && location.state.records
? (location.state.records = this.records)
: (location.state = {records: this.records})
}
......@@ -158,15 +169,33 @@ class App extends Component {
}
componentDidUpdate() {
const {location} = this.props
this.previousLocation = location.pathname.startsWith('/passport') ?
this.previousLocation.pathname === '/' ? location : this.previousLocation : location
this.setPreviousLocation()
if (!this.props.user.hasError && getParam('redirect')) {
window.location.href = getParam('redirect')
}
}
setPreviousLocation = () => {
const {location, history: {action}} = this.props
if (location.pathname.startsWith('/passport')) {
let index = this.records.findIndex(item => item.pathname.startsWith('/passport'))
this.previousLocation = index > 0
? this.records[index - 1]
: this.records.length
? this.records[this.records.length - 1]
: null
} else {
if (action === 'POP' || action === 'REPLACE') {
let index = this.records.findIndex(item => item.pathname.startsWith('/passport'))
this.previousLocation = index > 0 ? this.records[index - 1] : this.records[this.records.length - 1]
} else {
this.previousLocation = location
}
}
}
transformUser = res => {
let payload
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -422,6 +422,9 @@ Created by iconfont
<glyph glyph-name="play_hovericon" unicode="&#59011;" d="M512 896c282.763636 0 512-229.236364 512-512s-229.236364-512-512-512S0 101.236364 0 384 229.236364 896 512 896z m182.760727-552.680727a46.545455 46.545455 0 0 1 0 81.361454l-311.086545 172.846546A23.272727 23.272727 0 0 1 349.090909 577.163636v-386.327272a23.272727 23.272727 0 0 1 34.583273-20.363637l311.086545 172.846546z" horiz-adv-x="1024" />
<glyph glyph-name="gengduo" unicode="&#58960;" d="M511.616 883.328c-137.344 0-254.72-49.024-352.128-147.2C61.824 638.72 13.184 521.344 13.184 384c0-137.856 48.768-255.616 146.304-353.024 97.408-97.536 214.912-146.304 352.128-146.304 137.856 0 255.616 48.768 353.152 146.304 97.408 97.408 146.176 215.168 146.176 353.024 0 137.344-48.768 254.72-146.176 352.256C767.104 834.304 649.472 883.328 511.616 883.328zM198.528 696.96C285.312 783.744 389.76 827.136 511.616 827.136c122.496 0 227.072-43.392 313.856-130.176 86.784-86.144 130.176-190.464 130.176-312.96 0-122.496-43.392-227.072-130.176-313.856C738.688-16.768 633.984-60.16 511.616-60.16c-122.496 0-226.816 43.52-313.088 130.304C111.744 156.928 68.352 261.504 68.352 383.872c0 121.856 43.52 226.304 130.176 313.088z m469.12-313.088c0-14.208 4.736-26.496 14.336-36.608 10.112-9.472 22.016-14.336 35.712-14.336 13.568-0.128 26.496 5.12 36.096 14.72s14.848 22.528 14.72 36.096c-0.128 13.312-5.504 26.112-15.104 35.456-9.472 9.344-22.4 14.592-35.712 14.464-13.696 0-25.6-4.736-35.712-14.208-9.6-9.984-14.336-21.76-14.336-35.584z m-105.216 0c0 13.696-4.736 25.6-14.336 35.712-9.856 9.344-22.912 14.464-36.608 14.208-13.696 0-25.6-4.736-35.712-14.208-9.472-10.112-14.336-22.016-14.336-35.712 0-14.208 4.736-26.496 14.336-36.608 10.112-9.472 22.016-14.336 35.712-14.336 14.336 0 26.496 4.736 36.608 14.336 9.472 9.984 14.592 23.168 14.336 36.608z m-206.08 0c0 13.696-4.736 25.6-14.336 35.712-9.6 9.216-22.4 14.336-35.712 14.208-27.776 0-50.432-22.528-50.432-50.432 0-27.776 22.528-50.432 50.432-50.432 13.696 0 25.6 4.736 35.712 14.336 9.472 9.984 14.592 23.04 14.336 36.608z m0 0" horiz-adv-x="1024" />
</font>
......
......@@ -24,12 +24,21 @@ const options = {
class OpenApp extends Component {
callApp = new CallApp(options)
// callApp = new CallApp(options)
callApp = null
static defaultProps = {
text: '在APP打开'
}
componentWillMount() {
this.callApp = new CallApp({
...options,
path: this.props.path || '/'
});
}
handleClick = () => {
this.callApp.open({})
}
......
......@@ -7,10 +7,10 @@ const CAPTCHAID = '6b0f5f6c8f334f3693ee754ba5692e36'
class Captcha extends Component {
componentDidMount() {
const {getInstance, handleError, onVerify} = this.props
const el = document.getElementById('captcha')
const el = document.getElementById('captcha');
el && initCaptcha(function () {
initNECaptcha({
element: '#captcha',
element: el,
captchaId: CAPTCHAID,
mode: 'float',
width: 'auto',
......
......@@ -13,7 +13,7 @@ class HeaderBar extends Component {
if(browser.isWeixin && getParam('code') && getParam('state')){
window.history.go(-2)
}
if(state.record && state.record.length > 1){
if(state.records && state.records.length > 1){
window.history.go(-1);
}else{
window.location.href = window.location.origin
......
......@@ -3,7 +3,12 @@ import './index.scss'
const VList = (props) => {
return (
<li className='v-list-item' onClick={() => props.toDetail(props.id)}>
<li
className='v-list-item'
onClick={() => {
typeof props.toDetail === 'function' && props.toDetail(props.id)
}}
>
<div className="content">
<div className="cover">
{props.status}
......
import React, { Component } from 'react';
import QRCode from 'qrcode';
import { http } from "@/utils"
import './index.scss';
class FollowBarcode extends Component {
constructor(props) {
super(props);
this.state = {
url: ''
}
}
componentDidMount() {
console.log(this.props);
const { userInfo: { uid = '' } } = this.props;
if(uid) {
http.get(`${API['base-api']}/wx/user_temporary_qrcode/${uid}`).then((res) => {
const { errno, data } = res.data;
console.log(res);
if (errno == 0) {
this.setState({
url: data.url
});
return new Promise(resolve => {
QRCode.toDataURL(data.url, {}, function (err, url) {
this.setState({
codeUrl: url
})
});
resolve();
});
}
});
}
}
render() {
const { codeSrc } = this.state;
const { firendBaigainPrice, userInfo: { avatar }, money } = this.props;
return (
<div className='bargain-popup__barcode'>
<i className='bargain-popup__avatar' style={{backgroundImage: `url(${avatar})`}} />
{
firendBaigainPrice &&
<p className='bargain-popup__title'>谢谢你帮我砍了{money}元!</p>
}
<p className='bargain-popup__desc'>关注公众号,可以再砍一刀哦~</p>
<i className="bargain-popup__imgage" style={{backgroundImage: `url(${codeSrc})`}}></i>
</div>
);
}
}
export default FollowBarcode;
\ No newline at end of file
.bargain-popup__barcode {
width: 300px;
height: 185px;
margin: 200px auto 20px;
padding: 20px 0;
border-radius: 3px;
text-align: center;
background-color: $bg_fff;
}
.bargain-popup__avatar {
display: block;
width: 40px;
height: 40px;
margin: -40px auto 0;
border-radius: 50%;
background-size: cover;
}
.bargain-popup__title {
height: 16px;
margin: 10px auto 0;
font-size: 16px;
color: $color_FF4000;
line-height: 16px;
}
.bargain-popup__desc {
height: 12px;
margin: 10px auto 0;
font-size: 12px;
color: $color_666;
line-height: 12px;
}
.bargain-popup__imgage {
width: 86px;
height: 86px;
margin-top: 15px;
background-size: cover;
}
\ No newline at end of file
......@@ -167,8 +167,9 @@
float: right;
position: relative;
top: -20px;
width: 61px;
// width: 61px;
height: 24px;
padding: 0 10px;
background: $bg_FF4000;
border-radius: 12px;
font-size: 12px;
......@@ -533,8 +534,9 @@
.use-artifact {
background-color: $bg_fff;
width: 84px;
// width: 84px;
height: 24px;
padding: 0 13px;
font-size: 14px;
border: 1px solid $redprice;
border-radius: 12px;
......@@ -712,3 +714,28 @@
}
.bargain-popup__content {
text-align: center;
}
.bargain-popup__button--close {
font-size: 22px;
color: #fff;
}
.course-button__buy--done {
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 61px;
height: 18px;
margin: auto 0;
border-radius: 9px;
font-size: 12px;
color: $white;
text-align: center;
line-height: 18px;
background-color: $bg_active;
}
......@@ -6,7 +6,7 @@ import HeaderSearch from '../../common/HeaderSearch/index'
import { http, getParam } from "@/utils"
import Loading from '@/common/Loading'
import { connect } from 'react-redux';
import { StickyContainer } from "react-sticky";
import { StickyContainer, Sticky } from "react-sticky";
function stopScroll(e) {
......@@ -26,7 +26,8 @@ class Classify extends Component {
allClass: [],
data: [],
activeTab: decodeURIComponent(getParam('name')),
isLoading: true
isLoading: true,
top: 44
}
}
......@@ -34,6 +35,11 @@ class Classify extends Component {
componentDidMount() {
this.getTabs()
this.getList()
const el = document.querySelector('.search-nav');
this.setState({
top: el.offsetHeight
});
}
componentWillUnmount() {
......@@ -149,12 +155,12 @@ class Classify extends Component {
/>
<Loading isLoading={this.state.isLoading}>
<div className='class-content'>
<WhiteSpace/>
{/* <WhiteSpace/> */}
<div onClick={this.pulldown.bind(this)}>
{this.state.ispull ? top : bottom}
</div>
<StickyContainer>
<Tabs
{/* <Tabs
tabs={this.state.allClass}
animated={false}
page={page}
......@@ -162,6 +168,25 @@ class Classify extends Component {
renderTabBar={props => <div className={'custom-render-bar'}>
<Tabs.DefaultTabBar {...props}/>
</div>}
> */}
<Tabs
tabs={this.state.allClass}
animated={false}
page={page}
onChange={(tab) => this.ontabclick(tab)}
renderTabBar={props => {
return (
<Sticky>
{({ style }) => {
return (
<div style={{ ...style, top: `${this.state.top}px`, zIndex: 1 }}>
<Tabs.DefaultTabBar {...props} />
</div>
)
}}
</Sticky>
)
}}
>
<div className='tabs'>
<ul>
......
......@@ -16,7 +16,8 @@ html,body,#root {
}
.class-content {
padding: 88px 12px 0;
padding: 44px 12px 0;
// padding: 88px 12px 0;
position: relative;
.custom-render-bar{
......
......@@ -10,7 +10,7 @@ export const delCountryNum = () => ({
type: 'DEL_COUNTRY_NUM'
});
export default (state = {}, action) => {
export default (state = {num: 86, code: null}, action) => {
const { type, payload } = action;
switch (type) {
case ADD_COUNTRY_NUM:
......
......@@ -33,7 +33,8 @@ body {
}
.country-item {
margin: 0 12px;
margin-left: 12px;
padding-right: 22px;
}
.country-item__link {
......
......@@ -33,12 +33,8 @@ class Bargain extends Component {
}
// 获取助理好友
getBargainRankList = (id, type) => {
let data = {
courseId: id,
type: type
}
http.post(`${API.home}/m/bargain/rankList`, data).then((res) => {
getBargainRankList = (params = {}) => {
http.post(`${API.home}/m/bargain/rankList`, params).then((res) => {
if (res.data.code === 200) {
this.setState({
list: res.data.data.list,
......@@ -57,20 +53,26 @@ class Bargain extends Component {
courseId: getParam('id')
}
http.post(`${API.home}/m/bargain/courseDetail`, data).then((res) => {
if (res.data.code === 200) {
const { code, data, msg = '' } = res.data;
if (code === 200) {
this.setState({
barInfo: res.data.data,
barInfo: data,
// info: res.data.data,
// limitPeople: res.data.data.limit_people,
// bargainCode: res.data.data.bargain_code
})
if (res.data.data.bargain_status === 0) {
this.getBargainRankList(getParam('id'), 0)
});
// 砍价状态 0-砍价中,1砍价结束,待支付,2砍价过期(没有砍价记录没有砍价信息),3已购买
if (data.bargain_status === 0) {
this.getBargainRankList({
type: 0,
bargain_code: data.bargain_code
});
}
} else {
Toast.info(res.data.msg, 2)
Toast.info(msg, 2);
}
})
});
}
// 查看更多
......
......@@ -461,7 +461,7 @@ class Detail extends Component {
cart={true}
toHref={href}
/>
<CallApp className='toapp'/>
<CallApp className='toapp' path={`/detail/id=${getParam('id')}`} />
{/*弹幕*/}
<Barrage isShow={course_info.is_show}/>
......
......@@ -10,6 +10,8 @@ import Captcha from '@/common/Captcha';
import FollowQRcode from './../followQRcode';
import './index.scss';
import cookie from 'js-cookie'
import { Link } from "react-router-dom";
class RedPacket extends PureComponent {
......@@ -627,7 +629,6 @@ class RedPacket extends PureComponent {
bindInfo,
country
} = this.state;
// console.log(share_code);
const cls = classnames('popup-mask',{
'popup-mask--no': type !== 2
});
......@@ -851,12 +852,12 @@ class RedPacket extends PureComponent {
<Form className="popup-form__content">
<h4 className="popup-form__title">绑定手机号</h4>
<div className="popup-form__item">
<a
<Link
className="popup-form__button--num"
href={`/country?id=${getParam('id')}&share_code=${share_code}`}>
to={`/country?id=${getParam('id')}&share_code=${share_code}`}>
+{country.num}
<i className="iconfont iconiconfront-69"></i>
</a>
<i className="iconfont iconiconfront-69"/>
</Link>
<Field
name="tel"
render={({field}) => {
......
......@@ -7,10 +7,6 @@
color: $color_666;
}
.tel {
margin-bottom: 21px;
}
.verification {
margin-bottom: 21px;
}
......
import React, { Component } from 'react';
import './binding-tel.scss'
import { withFormik, Field, Form } from "formik";
import { validateTel, http, api, getParam } from "@/utils";
import { http, getParam } from "@/utils";
import { compose } from "redux";
import { connect } from "react-redux";
import { setCurrentUser } from "@/store/userAction";
import Captcha from '@/common/Captcha'
import {HeaderBar} from '@/common'
import { HeaderBar } from '@/common'
import ClearableInput from '@common/ClearableInput'
// import ClearableInput from '@common/ClearableInput'
import ClearableInput from '../common/clearableInputWithCountryCodes'
import Button from '../common/Button'
import VeriCodeInput from '../common/veriCodeInput'
import { Toast } from "antd-mobile";
......@@ -42,7 +43,8 @@ class BindingTel extends Component {
render() {
const {
values,
errors
errors,
country
} = this.props
return (
<>
......@@ -59,9 +61,7 @@ class BindingTel extends Component {
setFieldValue={form.setFieldValue}
placeholder={'请输入需要绑定的手机号'}
wrapperClass={'tel'}
icon={<i className={'iconfont iconshouji'}
style={{fontSize: '22px', left: '11px'}}
/>}
country={country}
/>
)
......@@ -77,18 +77,21 @@ class BindingTel extends Component {
icon={<i className={'iconfont iconduanxin'}
style={{fontSize: '20px', left: '12px'}}
/>}
placeholder={'验证码'}
account={values.tel}
tel={values.tel}
challenge={this.state.validate}
instance={this.state.captchaInstance}
action={'auth'}
country={country}
/>
)
}}
/>
<Captcha onVerify={this.onVerify} getInstance={this.getCaptchaInstance}/>
<Button className={'complete-btn'} active={values.tel && values.veriCode && isEmpty(errors)}>完成</Button>
<Button className={'complete-btn'}
active={values.tel && values.veriCode && isEmpty(errors)}>完成</Button>
</Form>
</div>
</>
......@@ -107,7 +110,7 @@ const formikConfig = {
validateOnChange: true,
validate(values) {
let errors = {}
if (!validateTel(values.tel)) {
if (!/\d/.test(values.tel)) {
errors.tel = '请输入正确的手机号'
}
if (!values.veriCode) {
......@@ -120,6 +123,7 @@ const formikConfig = {
phone_num: values.tel,
phone_code: values.veriCode,
mkey: getParam('mkey'),
area_code: props.country.num,
plat: 5
}).then(res => {
const data = res.data
......@@ -135,7 +139,7 @@ const formikConfig = {
stage: 'binding'
})
props.history.replace(`/passport/set-password`)
}else {
} else {
location.assign(data.data['jump_url'])
}
......@@ -143,17 +147,12 @@ const formikConfig = {
} else {
Toast.info(data.msg, 2, null, false)
}
/*props.setCurrentUser({
hasError,
data
})*/
})
}
}
export default compose(
connect(
null,
state => ({country: state.country}),
{setCurrentUser}
),
withFormik(formikConfig),
......
import React, { PureComponent } from 'react';
import { browser } from "@/utils";
import './loginWays.scss'
import more from '../../icons/more.png'
class LoginWays extends PureComponent {
state = {
ways: this.props.loginWays
}
componentDidMount() {
if (!browser.isWeixin) {
this.setState({
ways: this.state.ways.filter(item => item.text !== '微信')
})
}
ways: browser.isWeixin ? this.props.loginWays.slice(0, 2) : this.props.loginWays.slice(0, 1),
showMore: true
}
......@@ -22,6 +15,17 @@ class LoginWays extends PureComponent {
this.props.onClick(text)
}
filterWays = () => {
return browser.isWeixin ? this.props.loginWays : this.props.loginWays.filter(item => item.id !== 'wechat')
}
showMore = () => {
this.setState({
ways: this.filterWays(),
showMore: false
})
}
render() {
return (
<div className="login-ways">
......@@ -31,12 +35,19 @@ class LoginWays extends PureComponent {
this.state.ways.map((item, index) => {
return (
<li key={index} onClick={this.handleClick.bind(this, item.text)}>
<img src={item.logo} alt=""/>
<img src={item.logo} alt={item.text}/>
<p>{item.text}</p>
</li>
)
})
}
{
this.state.showMore &&
<li className={'more'} onClick={this.showMore}>
<img src={more} alt="更多"/>
<p>更多</p>
</li>
}
</ul>
</div>
);
......
import React, { Component } from 'react';
import ClearableInput from '@common/ClearableInput'
import './index.scss'
import { Link } from "react-router-dom";
class ClearableInputWithCountryCodes extends Component {
render() {
const {country, ...rest} = this.props
return (
<div className={'clearable-input-with-country-codes'}>
<div className="country-code">
<Link to={'/country'}>
+{country && country.num || 86}
<i className={'iconfont iconiconfront-69'}/>
</Link>
</div>
<ClearableInput {...rest}/>
</div>
);
}
}
export default ClearableInputWithCountryCodes;
\ No newline at end of file
.clearable-input-with-country-codes {
display: flex;
border: 1px solid #ccc;
border-radius: 3px;
margin-bottom: 24px;
.clearable-input-wrapper {
margin-bottom: 0;
flex: 1 1 auto;
input {
padding-left: 10px;
border: none;
width: 100%;
padding-right: 34px;
}
}
.country-code {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
color: #333;
width: 63px;
text-align: center;
border-right: 1px solid #ccc;
.iconfont {
margin-left: 3px;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss'
import Input from '../Input'
import { Link } from "react-router-dom";
class InputWithCountryCodes extends Component {
render() {
const {country, ...rest} = this.props
return (
<div className={'input-with-country-codes'}>
<div className="country-codes">
<Link to={'/country'}>
+{country && country.num || 86}
<i className={'iconfont iconiconfront-69'}/>
</Link>
</div>
<Input {...rest}/>
</div>
);
}
}
export default InputWithCountryCodes;
\ No newline at end of file
.input-with-country-codes {
display: flex;
border: 1px solid #ccc;
border-radius: 3px;
margin-bottom: 24px;
.tel-input {
margin-bottom: 0;
.input {
padding-left: 10px;
border: none;
}
}
.country-codes {
flex-shrink: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
color: #333;
width: 63px;
text-align: center;
border-right: 1px solid #ccc;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './veri-code-input.scss'
import { http, validateEmail, validateTel } from '@/utils';
import { http, validateEmail } from '@/utils';
import { Toast } from "antd-mobile";
import { has } from 'lodash'
......@@ -47,8 +47,8 @@ class VeriCodeInput extends Component {
}
getType = () => {
const {account} = this.props
if (validateEmail(account)) {
const {email} = this.props
if (validateEmail(email)) {
return 'email'
}
}
......@@ -61,9 +61,9 @@ class VeriCodeInput extends Component {
}
sendEmail = () => {
const {account, challenge} = this.props
const {email, challenge} = this.props
http.post(`${API['passport-api']}/send_email_code`, {
email: account,
email,
challenge
}).then(res => {
if (res.data.errno === 0) {
......@@ -79,14 +79,15 @@ class VeriCodeInput extends Component {
}
sendSMS = () => {
const {action, tel, account, challenge, checking} = this.props
if (!tel && !account) {
Toast.info('请输入手机号或邮箱地址')
const {action, tel, account, challenge, checking, country} = this.props
if (!tel) {
Toast.info('请输入手机号')
return
}
http.post(`${API['passport-api']}/quick_sms`, {
phone_num: tel || account,
action: action || 'login',
area_code: country.num,
challenge,
checking
}).then(res => {
......@@ -103,7 +104,7 @@ class VeriCodeInput extends Component {
validate = () => {
const {tel, challenge, account} = this.props
const {tel, challenge, email} = this.props
let hasTel = has(this.props, 'tel')
let content
......@@ -111,15 +112,15 @@ class VeriCodeInput extends Component {
if (!tel) {
content = '手机号码不能为空'
}
if (!validateTel(tel)) {
if (!/\d/.test(tel)) {
content = '请输入正确格式的手机号码'
}
} else {
if (!account) {
content = '手机号或电子邮件不能为空'
if (!email) {
content = '电子邮件不能为空'
}
if (!validateTel(account) && !validateEmail(account)) {
content = '请输入正确格式的手机号或电子邮件'
if (!validateEmail(email)) {
content = '请输入正确格式的电子邮件'
}
}
......
......@@ -4,6 +4,13 @@
.content {
padding: 38px 36px;
text-align: center;
.to-email{
line-height: 55px;
font-size: 15px;
color: #666;
}
}
......@@ -14,10 +21,6 @@
background: #56abff;
}
.tel-input {
margin-bottom: 21px;
}
.verify-code {
margin-bottom: 21px;
}
......@@ -25,4 +28,5 @@
.next_step {
margin-top: 32px;
}
}
\ No newline at end of file
......@@ -6,10 +6,12 @@ import { withFormik, Form, Field } from 'formik';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { Toast } from "antd-mobile";
import { HeaderBar, Captcha, ClearableInput } from "@/common";
import { validateTel, validateEmail, http, api } from "@/utils";
import { HeaderBar, Captcha } from "@/common";
import ClearableInput from '../common/clearableInputWithCountryCodes'
import { http } from "@/utils";
import { quickLogin } from '@/store/userAction';
import OnSubmissionError from '../common/OnSubmissionError'
import { Link } from "react-router-dom";
class ForgotPassword extends Component {
......@@ -42,7 +44,8 @@ class ForgotPassword extends Component {
render() {
const {
values,
isValid
isValid,
country
} = this.props
return (
<div className={'forgot-password'}>
......@@ -50,18 +53,16 @@ class ForgotPassword extends Component {
<div className="content">
<Form className='forgot-password-form'>
<Field
name={'account'}
name={'tel'}
render={({field, form}) => {
return (
<ClearableInput
{...field}
type={'tel'}
placeholder={'请输入注册时的邮箱账号或手机号'}
placeholder={'请输入注册时的手机号'}
wrapperClass={'tel-input'}
setFieldValue={form.setFieldValue}
icon={<i className={'iconfont iconshouji'}
style={{fontSize: '22px', left: '11px'}}
/>}
country={country}
/>)
}}
/>
......@@ -77,11 +78,12 @@ class ForgotPassword extends Component {
icon={<i className={'iconfont iconduanxin'}
style={{fontSize: '20px', left: '12px'}}
/>}
account={values.account}
tel={values.tel}
challenge={this.state.validate}
instance={this.state.captchaInstance}
action={'auth'}
checking={1}
country={country}
/>
)
}}
......@@ -90,6 +92,7 @@ class ForgotPassword extends Component {
<OnSubmissionError callback={this.onSubmissionError}/>
<Captcha getInstance={this.getCaptchaInstance} onVerify={this.onVerify}/>
<Button className={'next_step'} active={isValid}>下一步</Button>
<Link className={'to-email'} to={`/passport/forgot-password-email`} replace>邮箱找回</Link>
</Form>
</div>
</div>
......@@ -101,37 +104,26 @@ class ForgotPassword extends Component {
const formikConfig = {
mapPropsToValues: () => ({
account: '',
tel: '',
veriCode: ''
}),
validateOnChange: true,
validateOnBlur: true,
validate: values => {
let errors = {}
if (!validateTel(values.account) && !validateEmail(values.account)) {
errors.account = '请输入正确的手机号或邮箱地址'
if (!/\d/.test(values.tel)) {
errors.tel = '请输入正确的手机号'
}
values.veriCode.toString().length !== 6 && (errors.veriCode = '验证码格式不正确')
return errors
},
handleSubmit(values, {props}) {
let account, address
if (validateEmail(values.account)) {
account = 'email'
address = 'check_email_code'
sessionStorage.setItem('r_type', 'email')
sessionStorage.setItem('email', values.account)
} else {
account = 'phone'
address = 'check_phone_code'
sessionStorage.setItem('r_type', 'phone')
sessionStorage.setItem('tel', values.account)
}
http.post(`${API['passport-api']}/${address}`, {
[account]: values.account,
code: values.veriCode
sessionStorage.setItem('r_type', 'phone')
sessionStorage.setItem('tel', values.tel)
http.post(`${API['passport-api']}/check_phone_code`, {
phone: values.tel,
code: values.veriCode,
area_code: props.country.num
}).then(res => {
if (res.data.errno == 0) {
props.history.push('/passport/set-password', {from: props.location})
......@@ -145,7 +137,7 @@ const formikConfig = {
export default compose(
connect(
null,
state => ({country: state.country}),
{quickLogin}
),
withFormik(formikConfig)
......
import React, { Component } from 'react'
import './index.scss'
import VeriCodeInput from '../common/veriCodeInput'
import Button from '../common/Button'
import { withFormik, Form, Field } from 'formik';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { Toast } from "antd-mobile";
import { HeaderBar, Captcha, ClearableInput } from "@/common";
import { validateEmail, http, api } from "@/utils";
import { quickLogin } from '@/store/userAction';
import OnSubmissionError from '../common/OnSubmissionError'
import { Link } from "react-router-dom";
class ForgotPassword extends Component {
state = {
validate: null,
captchaInstance: null
}
getCaptchaInstance = instance => {
this.setState({
captchaInstance: instance
})
}
onVerify = (err, data) => {
if (err) {
console.log(err)
} else {
this.setState({
validate: data.validate
})
}
}
onSubmissionError = () => {
const errors = Object.values(this.props.errors);
errors.length && Toast.info(errors[0], 2, null, false)
}
render() {
const {
values,
isValid
} = this.props
return (
<div className={'forgot-password-email'}>
<HeaderBar title='忘记密码' arrow={true}/>
<div className="content">
<Form className='forgot-password-form'>
<Field
name={'email'}
render={({field, form}) => {
return (
<ClearableInput
{...field}
type={'email'}
placeholder={'请输入注册时的邮箱账号'}
wrapperClass={'email-input'}
setFieldValue={form.setFieldValue}
/>)
}}
/>
{
this.state.validate &&
<Field
name='veriCode'
render={({field}) => {
return (
<VeriCodeInput
{...field}
className={'verify-code'}
icon={<i className={'iconfont iconduanxin'}
style={{fontSize: '20px', left: '12px'}}
/>}
email={values.email}
challenge={this.state.validate}
instance={this.state.captchaInstance}
action={'auth'}
checking={1}
/>
)
}}
/>
}
<OnSubmissionError callback={this.onSubmissionError}/>
<Captcha getInstance={this.getCaptchaInstance} onVerify={this.onVerify}/>
<Button className={'next_step'} active={isValid}>下一步</Button>
<Link className={'to-phone'} to={'/passport/forgot-password'} replace>手机号找回</Link>
</Form>
</div>
</div>
);
}
}
const formikConfig = {
mapPropsToValues: () => ({
email: '',
veriCode: ''
}),
validateOnChange: true,
validateOnBlur: true,
validate: values => {
let errors = {}
if (!validateEmail(values.email)) {
errors.email = '请输入正确的邮箱地址'
}
values.veriCode.toString().length !== 6 && (errors.veriCode = '验证码格式不正确')
return errors
},
handleSubmit(values, {props}) {
sessionStorage.setItem('r_type', 'email')
sessionStorage.setItem('email', values.email)
http.post(`${API['passport-api']}/check_email_code`, {
email: values.email,
code: values.veriCode
}).then(res => {
if (res.data.errno == 0) {
props.history.push('/passport/set-password', {from: props.location})
} else {
Toast.info(res.data.msg, 2, null, false)
}
})
},
}
export default compose(
connect(
null,
{quickLogin}
),
withFormik(formikConfig)
)(ForgotPassword)
\ No newline at end of file
.forgot-password-email {
height: 100%;
.content {
padding: 38px 36px;
text-align: center;
.to-phone{
line-height: 55px;
font-size: 15px;
color: #666;
}
.email-input{
margin-bottom: 21px;
input{
padding-left: 10px;
}
}
}
.place {
width: 100%;
height: 39px;
margin-bottom: 33px;
background: #56abff;
}
.verify-code {
margin-bottom: 21px;
}
.next_step {
margin-top: 32px;
}
}
\ No newline at end of file
......@@ -8,14 +8,15 @@ import AccountLogin from './accountLogin'
import ForgotPassword from './forgotPassword'
import SetPassword from './setPassword'
import BindingTel from './bindingTel'
import ForgotPasswordEmail from './forgotPasswordEmail'
import { connect } from "react-redux";
import { compose } from "redux";
import {getParam} from "@/utils";
import account from './account.png'
import qq from './qq.png'
import sina from './sina.png'
import wechat from './wechat.png'
import { getParam } from "@/utils";
import account from './icons/account.png'
import qq from './icons/qq.png'
import sina from './icons/sina.png'
import wechat from './icons/wechat.png'
class Passport extends Component {
......@@ -32,23 +33,27 @@ class Passport extends Component {
loginWays: [
{
logo: account,
text: '账号登录'
text: '账号登录',
id: 'account'
},
{
logo: wechat,
text: '微信',
url: ''
url: '',
id: 'wechat'
},
{
logo: qq,
text: 'QQ',
url: `${API["passport-api"]}/mob/qqlogin?redirect_url=${this.redirectURL}`
url: `${API["passport-api"]}/mob/qqlogin?redirect_url=${this.redirectURL}`,
id: 'qq'
},
{
logo: sina,
text: '新浪',
url: `${API['passport-api']}/mob/sinalogin?redirect_url=${this.redirectURL}`
},
url: `${API['passport-api']}/mob/sinalogin?redirect_url=${this.redirectURL}`,
id: 'sina'
}
]
}
}
......@@ -95,6 +100,7 @@ class Passport extends Component {
}}/>
<Route path={match.url + '/account-login'} component={AccountLogin}/>
<Route path={match.url + '/forgot-password'} component={ForgotPassword}/>
<Route path={match.url + '/forgot-password-email'} component={ForgotPasswordEmail}/>
<Route path={match.url + '/set-password'} component={SetPassword}/>
<Route path={match.url + '/binding-tel'} component={BindingTel}/>
</Switch>
......
import React, { Component } from 'react'
import './wechatLogin.scss'
import Input from "../common/Input"
// import Input from "../common/Input"
import Input from '../common/inputWithCountryCodes'
import LoginButton from '../common/LoginButton'
import LoginWays from '../common/LoginWays'
import Header from '../common/Header'
......@@ -12,7 +13,6 @@ import { connect } from 'react-redux';
import { compose } from 'redux';
import { isEmpty } from 'lodash'
import { Toast } from 'antd-mobile';
import { validateTel, getParam } from "@/utils";
import { HeaderBar } from "@/common";
......@@ -69,7 +69,8 @@ class Login extends Component {
const {
loginWays,
errors,
values
values,
country
} = this.props
return (
<div className='login'>
......@@ -84,9 +85,7 @@ class Login extends Component {
type={'tel'}
placeholder={'手机号快捷登录(免注册)'}
wrapperClass={'tel-input'}
icon={<i className={'iconfont iconshouji'}
style={{fontSize: '22px', left: '10px'}}
/>}
country={country}
/>
)}
>
......@@ -108,6 +107,7 @@ class Login extends Component {
errors={errors}
placeholder={'请输入验证码'}
instance={this.state.captchaInstance}
country={country}
/>
)}
/>
......@@ -132,7 +132,8 @@ const FormikConfig = {
handleSubmit(values, {props}) {
props.quickLogin({
phone_num: values.tel,
phone_code: values.veriCode
phone_code: values.veriCode,
area_code: props.country.num
}).then(res => {
if (res.hasError) {
Toast.info(res.msg);
......@@ -146,7 +147,7 @@ const FormikConfig = {
validateOnChange: true,
validate: (values) => {
let errors = {}
if (!validateTel(values.tel)) {
if (!/\d/.test(values.tel)) {
errors.tel = '请填写正确格式的手机号'
}
if (!/[0-9]{6}/.test(values.veriCode)) {
......@@ -158,7 +159,7 @@ const FormikConfig = {
export default compose(
connect(
null,
state => ({country: state.country}),
{quickLogin}
),
withFormik(FormikConfig),
......
......@@ -8,9 +8,9 @@
padding: 0 38px;
flex: 1 0 auto;
.tel-input {
/*.tel-input {
margin-bottom: 24px;
}
}*/
.verification{
margin-bottom: 24px;
......
......@@ -16,6 +16,7 @@ import { connect } from "react-redux";
class SetPassword extends Component {
render() {
let {values, errors, location} = this.props
let {from} = location.state || {from: {pathname: '/'}}
......
......@@ -12,16 +12,19 @@ class Search extends PureComponent {
state = {
searchHistory: JSON.parse(localStorage.getItem('searchHistory')) || [],
hot_words: [],
defaultWord: '',
searchList: [],
value: '',
isLoading: true
}
async componentDidMount() {
const res = await http.get(`${API['search-api']}/search_hot_word`)
if (res.data.errno === 0) {
const res = await http.get(`${API['search-api']}/search_hot_word`);
const { errno, data } = res.data;
if (errno === 0) {
this.setState({
hot_words: res.data.data.info.hot_words,
hot_words: data.info.hot_words,
defaultWord: data.info.recommend_word,
isLoading: false
})
}
......@@ -39,11 +42,15 @@ class Search extends PureComponent {
}
handleSearch = () => {
this.state.value && this.props.history.push(`/search-result?word=${encodeURIComponent(this.state.value)}`)
const { defaultWord, value } = this.state;
const val = value || defaultWord;
val && this.props.history.push(`/search-result?word=${encodeURIComponent(val)}`)
}
storeHistory = keyword => {
localStorage.setItem('searchHistory', JSON.stringify([...this.state.searchHistory, keyword]))
const { searchHistory } = this.state;
const data = searchHistory.some(item => item === keyword)? searchHistory : searchHistory.concat([keyword]);
localStorage.setItem('searchHistory', JSON.stringify(data));
}
......@@ -53,7 +60,7 @@ class Search extends PureComponent {
<div className="search-page">
<SearchHead
searchHistory={this.state.searchHistory}
value={this.state.value}
value={this.state.value || this.state.defaultWord}
handleChange={this.handleChange}
handleSearch={this.handleSearch}
/>
......
......@@ -25,8 +25,10 @@ class SearchHead extends PureComponent {
}
storeKeyword = () => {
let {searchHistory = [], value} = this.props
value && localStorage.setItem('searchHistory', JSON.stringify([...searchHistory, value]))
const {searchHistory = [], value} = this.props;
const data = searchHistory.some(item =>item === value)? searchHistory : searchHistory.concat([value]);
// value && localStorage.setItem('searchHistory', JSON.stringify([...searchHistory, value]))
localStorage.setItem('searchHistory', JSON.stringify(data));
}
changeFontColor = (isFocus) => {
......
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