同意{"<<服务条款>>"}和
@@ -55,6 +61,6 @@ const LoginForm = ({ history, jumpToLogin }) => {
);
-};
+});
-export default withRouter(LoginForm);
+export default LoginForm;
diff --git a/src/application/User/Login/components/LoginForm/style.js b/src/application/User/Login/components/LoginForm/style.js
index 06cb146..ee7cd8e 100644
--- a/src/application/User/Login/components/LoginForm/style.js
+++ b/src/application/User/Login/components/LoginForm/style.js
@@ -61,6 +61,216 @@ export const BeautyCheckBox = styled.ul`
a {
color: #d79088;
}
+
+ &.shake-horizontal {
+ animation-name: shake-horizontal;
+ animation-duration: 400ms;
+ animation-timing-function: ease-in-out;
+ animation-iteration-count: 5s;
+ animation-play-state: running;
+ }
+ @keyframes shake-horizontal {
+ 2% {
+ transform: translate(-5px, 0) rotate(0);
+ }
+
+ 4% {
+ transform: translate(8px, 0) rotate(0);
+ }
+
+ 6% {
+ transform: translate(8px, 0) rotate(0);
+ }
+
+ 8% {
+ transform: translate(9px, 0) rotate(0);
+ }
+
+ 10% {
+ transform: translate(-7px, 0) rotate(0);
+ }
+
+ 12% {
+ transform: translate(1px, 0) rotate(0);
+ }
+
+ 14% {
+ transform: translate(-4px, 0) rotate(0);
+ }
+
+ 16% {
+ transform: translate(7px, 0) rotate(0);
+ }
+
+ 18% {
+ transform: translate(8px, 0) rotate(0);
+ }
+
+ 20% {
+ transform: translate(-7px, 0) rotate(0);
+ }
+
+ 22% {
+ transform: translate(9px, 0) rotate(0);
+ }
+
+ 24% {
+ transform: translate(8px, 0) rotate(0);
+ }
+
+ 26% {
+ transform: translate(-2px, 0) rotate(0);
+ }
+
+ 28% {
+ transform: translate(5px, 0) rotate(0);
+ }
+
+ 30% {
+ transform: translate(6px, 0) rotate(0);
+ }
+
+ 32% {
+ transform: translate(4px, 0) rotate(0);
+ }
+
+ 34% {
+ transform: translate(3px, 0) rotate(0);
+ }
+
+ 36% {
+ transform: translate(7px, 0) rotate(0);
+ }
+
+ 38% {
+ transform: translate(-1px, 0) rotate(0);
+ }
+
+ 40% {
+ transform: translate(3px, 0) rotate(0);
+ }
+
+ 42% {
+ transform: translate(10px, 0) rotate(0);
+ }
+
+ 44% {
+ transform: translate(3px, 0) rotate(0);
+ }
+
+ 46% {
+ transform: translate(-9px, 0) rotate(0);
+ }
+
+ 48% {
+ transform: translate(6px, 0) rotate(0);
+ }
+
+ 50% {
+ transform: translate(-8px, 0) rotate(0);
+ }
+
+ 52% {
+ transform: translate(6px, 0) rotate(0);
+ }
+
+ 54% {
+ transform: translate(1px, 0) rotate(0);
+ }
+
+ 56% {
+ transform: translate(5px, 0) rotate(0);
+ }
+
+ 58% {
+ transform: translate(-4px, 0) rotate(0);
+ }
+
+ 60% {
+ transform: translate(3px, 0) rotate(0);
+ }
+
+ 62% {
+ transform: translate(-5px, 0) rotate(0);
+ }
+
+ 64% {
+ transform: translate(7px, 0) rotate(0);
+ }
+
+ 66% {
+ transform: translate(-8px, 0) rotate(0);
+ }
+
+ 68% {
+ transform: translate(-2px, 0) rotate(0);
+ }
+
+ 70% {
+ transform: translate(-5px, 0) rotate(0);
+ }
+
+ 72% {
+ transform: translate(1px, 0) rotate(0);
+ }
+
+ 74% {
+ transform: translate(1px, 0) rotate(0);
+ }
+
+ 76% {
+ transform: translate(-9px, 0) rotate(0);
+ }
+
+ 78% {
+ transform: translate(6px, 0) rotate(0);
+ }
+
+ 80% {
+ transform: translate(8px, 0) rotate(0);
+ }
+
+ 82% {
+ transform: translate(10px, 0) rotate(0);
+ }
+
+ 84% {
+ transform: translate(-6px, 0) rotate(0);
+ }
+
+ 86% {
+ transform: translate(-1px, 0) rotate(0);
+ }
+
+ 88% {
+ transform: translate(5px, 0) rotate(0);
+ }
+
+ 90% {
+ transform: translate(-1px, 0) rotate(0);
+ }
+
+ 92% {
+ transform: translate(7px, 0) rotate(0);
+ }
+
+ 94% {
+ transform: translate(-3px, 0) rotate(0);
+ }
+
+ 96% {
+ transform: translate(-7px, 0) rotate(0);
+ }
+
+ 98% {
+ transform: translate(-4px, 0) rotate(0);
+ }
+
+ 0%,
+ 100% {
+ transform: translate(0, 0) rotate(0);
+ }
+ }
`;
export const OtherLoginLink = styled.div`
diff --git a/src/application/User/Login/components/PhoneForm/index.js b/src/application/User/Login/components/PhoneForm/index.js
index 2174cdf..6bdd9ec 100644
--- a/src/application/User/Login/components/PhoneForm/index.js
+++ b/src/application/User/Login/components/PhoneForm/index.js
@@ -1,4 +1,4 @@
-import React, { useState } from "react";
+import React, { useState, useCallback } from "react";
import { Header, Container } from "./style";
import { trimPhone } from "../../../../../api/utils";
import StepOne from "./step-one";
@@ -9,12 +9,15 @@ const PhoneForm = props => {
const [phone, setPhone] = useState("");
//验证码触发登录操作
- const triggerLogin = vcode => {
- loginByVcode(trimPhone(phone), vcode);
- };
+ const triggerLogin = useCallback(
+ vcode => {
+ loginByVcode(trimPhone(phone), vcode);
+ },
+ [phone, loginByVcode]
+ );
//切换手机号码和验证码表单
- const onClickNext = () => {
+ const triggerSentVcode = () => {
sentVcode(trimPhone(phone));
};
@@ -46,11 +49,15 @@ const PhoneForm = props => {
{!sentStatus ? (
) : (
-
+
)}
);
diff --git a/src/application/User/Login/components/PhoneForm/step-one/index.js b/src/application/User/Login/components/PhoneForm/step-one/index.js
index c6f6a1b..864cf4a 100644
--- a/src/application/User/Login/components/PhoneForm/step-one/index.js
+++ b/src/application/User/Login/components/PhoneForm/step-one/index.js
@@ -6,7 +6,7 @@ const StepOne = props => {
const inputRef = useRef();
useEffect(() => {
inputRef.current.focus();
- }, []);
+ });
return (
<>
diff --git a/src/application/User/Login/components/PhoneForm/step-two/index.js b/src/application/User/Login/components/PhoneForm/step-two/index.js
index 3c1fc63..ff5584e 100644
--- a/src/application/User/Login/components/PhoneForm/step-two/index.js
+++ b/src/application/User/Login/components/PhoneForm/step-two/index.js
@@ -2,25 +2,26 @@ import React, { useState, useRef, useEffect } from "react";
import { VcodeBox, Container } from "./style";
const maxLength = 4;
+const sentPeriod = 60;
+let theTimer;
const StepTwo = props => {
- const { phone, triggerLogin } = props;
+ const { phone, triggerLogin, reSentVcode } = props;
const [cursorIndex, setCursorIndex] = useState(0);
const [vcode, setVcode] = useState("");
- const [timer, setTimer] = useState(60);
+ const [timer, setTimer] = useState(sentPeriod);
const inputRef = useRef();
-
useEffect(() => {
inputRef.current.focus();
- let theTimer;
- if (!theTimer) {
- theTimer = setInterval(() => {
- setTimer(timer => timer - 1);
- }, 1000);
+ if (timer === 0) {
+ clearInterval(theTimer);
+ }
+ if (timer !== sentPeriod) {
+ return;
}
- return () => {
- clearTimeout(theTimer);
- };
- }, [vcode]);
+ theTimer = setInterval(() => {
+ setTimer(timer => timer - 1);
+ }, 1000);
+ }, [timer]);
useEffect(() => {
if (vcode.length === 4) {
@@ -30,13 +31,15 @@ const StepTwo = props => {
const onChangeVcode = e => {
const val = e.target.value;
- if (!val) {
- return;
- }
setVcode(val);
setCursorIndex(val.split("").length);
};
+ const onClickSentVcode = () => {
+ reSentVcode();
+ setTimer(sentPeriod);
+ };
+
return (
验证码已发送至
@@ -44,7 +47,13 @@ const StepTwo = props => {
{phone.replace(/(\d{3})\s(\d{4})\s(\d{4})/g, "+86 $1 **** $3")}
- {timer}S
+ {timer ? (
+ {timer}S
+ ) : (
+
+ 重新发送
+
+ )}
验证码:
diff --git a/src/application/User/Login/components/PhoneForm/step-two/style.js b/src/application/User/Login/components/PhoneForm/step-two/style.js
index 9450fbd..bf7091a 100644
--- a/src/application/User/Login/components/PhoneForm/step-two/style.js
+++ b/src/application/User/Login/components/PhoneForm/step-two/style.js
@@ -12,6 +12,9 @@ export const Container = styled.div`
padding: 0 25px;
margin-top: 10px;
justify-content: space-between;
+ .sentBtn {
+ color: #0066cc;
+ }
}
`;
export const VcodeBox = styled.div`
@@ -37,7 +40,7 @@ export const VcodeBox = styled.div`
.v-code input {
position: absolute;
top: -100%;
- left: -666666px;
+ left: -100%;
opacity: 0;
}
.v-code .line {
diff --git a/src/application/User/Login/index.js b/src/application/User/Login/index.js
index 32e3d66..d200d76 100644
--- a/src/application/User/Login/index.js
+++ b/src/application/User/Login/index.js
@@ -1,5 +1,6 @@
-import React, { useState } from "react";
+import React, { useState, useRef, useEffect } from "react";
import { Container, LogoImg, LogoContainer, LoginContainer } from "./style";
+import { withRouter } from "react-router-dom";
import * as actionCreators from "./store/actionCreators";
import LoginForm from "./components/LoginForm";
import PhoneForm from "./components/PhoneForm";
@@ -8,16 +9,46 @@ import { CSSTransition } from "react-transition-group";
import { connect } from "react-redux";
const Login = props => {
- const { LoginByVcodeDispatch, sentVcodeDispatch, sentStatus } = props;
+ const {
+ LoginByVcodeDispatch,
+ sentVcodeDispatch,
+ sentStatus,
+ loginStatus,
+ changeSentStatusDispatch,
+ history
+ } = props;
const [inPhone, setInPhone] = useState(false);
+ const [agreed, setAgreed] = useState(false);
+ const checkBoxRef = useRef();
+
+ useEffect(() => {
+ if (loginStatus) {
+ history.push("/recommend");
+ }
+ }, [loginStatus, history]);
+
+ const jumpToIndex = () => {
+ history.push("/recommend");
+ };
+
const jumpToLogin = method => {
+ if (!agreed) {
+ // alert("请同意条款");
+ checkBoxRef.current.classList.add("shake-horizontal");
+ setTimeout(() => {
+ checkBoxRef.current.classList.remove("shake-horizontal");
+ }, 500);
+ return;
+ }
if (method === "phone") {
setInPhone(true);
}
};
+
const onPhoneBack = () => {
setInPhone(false);
};
+
return (
<>
@@ -27,10 +58,21 @@ const Login = props => {
-
+
-
+ changeSentStatusDispatch()}
+ >
{
// 映射Redux全局的state到组件的props上
const mapStateToProps = state => ({
userInfo: state.getIn(["user", "userInfo"]),
- sentStatus: state.getIn(["user", "sentStatus"])
+ sentStatus: state.getIn(["user", "sentStatus"]),
+ loginStatus: state.getIn(["user", "loginStatus"])
});
// 映射dispatch到props上
const mapDispatchToProps = dispatch => {
@@ -61,6 +104,9 @@ const mapDispatchToProps = dispatch => {
},
sentVcodeDispatch(phone) {
dispatch(actionCreators.sentVcode(phone));
+ },
+ changeSentStatusDispatch() {
+ dispatch(actionCreators.saveSentStatus(false));
}
};
};
@@ -68,4 +114,4 @@ const mapDispatchToProps = dispatch => {
export default connect(
mapStateToProps,
mapDispatchToProps
-)(React.memo(Login));
+)(React.memo(withRouter(Login)));
diff --git a/src/application/User/Login/store/actionCreators.js b/src/application/User/Login/store/actionCreators.js
index ae12f44..3753f5a 100644
--- a/src/application/User/Login/store/actionCreators.js
+++ b/src/application/User/Login/store/actionCreators.js
@@ -3,7 +3,11 @@ import {
sentVcodeRequest,
loginByVcodeRequest
} from "../../../../api/request";
-import { CHANGE_USER_INFO, CHANGE_SENT_STATUS } from "./constants";
+import {
+ CHANGE_USER_INFO,
+ CHANGE_SENT_STATUS,
+ CHANGE_LOGIN_STATUS
+} from "./constants";
export const saveUserInfo = data => ({
type: CHANGE_USER_INFO,
@@ -15,6 +19,11 @@ export const saveSentStatus = data => ({
data
});
+export const saveLoginStatus = data => ({
+ type: CHANGE_LOGIN_STATUS,
+ data
+});
+
export const loginByPhone = (phone, password) => {
return dispatch => {
loginByPhoneRequest(phone, password)
@@ -31,7 +40,10 @@ export const loginByVcode = (phone, vcode) => {
return dispatch => {
loginByVcodeRequest(phone, vcode)
.then(res => {
- dispatch(saveUserInfo(res));
+ if (res.code === 200) {
+ dispatch(saveUserInfo(res));
+ dispatch(saveLoginStatus(true));
+ }
})
.catch(() => {
console.log("登录失败!");
diff --git a/src/application/User/Login/store/constants.js b/src/application/User/Login/store/constants.js
index 06924da..33e0559 100644
--- a/src/application/User/Login/store/constants.js
+++ b/src/application/User/Login/store/constants.js
@@ -1,3 +1,5 @@
export const CHANGE_USER_INFO = "user/login/CHANGE_USER_INFO";
export const CHANGE_SENT_STATUS = "user/login/CHANGE_SENT_STATUS";
+
+export const CHANGE_LOGIN_STATUS = "user/login/CHANGE_LOGIN_STATUS";
diff --git a/src/application/User/Login/store/reducer.js b/src/application/User/Login/store/reducer.js
index f80d564..693f585 100644
--- a/src/application/User/Login/store/reducer.js
+++ b/src/application/User/Login/store/reducer.js
@@ -3,7 +3,8 @@ import { fromJS } from "immutable";
const defaultState = fromJS({
userInfo: {},
- sentStatus: false
+ sentStatus: false,
+ loginStatus: false
});
export default (state = defaultState, action) => {
@@ -12,6 +13,8 @@ export default (state = defaultState, action) => {
return state.set("userInfo", action.data);
case actionTypes.CHANGE_SENT_STATUS:
return state.set("sentStatus", action.data);
+ case actionTypes.CHANGE_LOGIN_STATUS:
+ return state.set("loginStatus", action.data);
default:
return state;
}