Login & Register
This commit is contained in:
@@ -40,22 +40,35 @@ const Page: React.FC<DispatchProp & CheckModelState> = ({
|
||||
);
|
||||
}
|
||||
|
||||
let title;
|
||||
if (pageStep === PageStep.Register) {
|
||||
title = formatMessage({ id: 'check.titleRegister' });
|
||||
} else if (pageStep === PageStep.Reset || pageStep === PageStep.ResetSuccess) {
|
||||
title = formatMessage({ id: 'check.titleReset' });
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.check}>
|
||||
{
|
||||
pageStep !== PageStep.Check &&
|
||||
<Header
|
||||
title={title}
|
||||
className={styles.header}
|
||||
onReturn={() => dispatch({ type: 'check/back' })}
|
||||
/>
|
||||
}
|
||||
|
||||
<div className="cover">
|
||||
<div className="image">
|
||||
<FittedImage fit="contain" src={bgPic} />
|
||||
{(
|
||||
pageStep === PageStep.Check ||
|
||||
pageStep === PageStep.Login
|
||||
) && (
|
||||
<div className="cover">
|
||||
<div className="image">
|
||||
<FittedImage fit="contain" src={bgPic} />
|
||||
</div>
|
||||
<span>{formatMessage({ id: 'app.name' })}</span>
|
||||
</div>
|
||||
<span>{formatMessage({ id: 'app.name' })}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{{
|
||||
[PageStep.Check]: <CheckPage />,
|
||||
|
||||
@@ -21,7 +21,7 @@ const LoginPage: React.FC<DispatchProp & CheckModelState> = ({
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="item gradient"
|
||||
className="item gradient submit"
|
||||
type="primary"
|
||||
loading={submitting}
|
||||
onClick={() => dispatch({ type: 'check/submitLogin' })}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { delay } from 'dva/saga';
|
||||
import { PageState, AreaCode, AreaCodes } from '@/types/common';
|
||||
import { getAreaCodes, getUserInfo } from '@/services/common';
|
||||
import { validPhoneInput, validPwdInput, validPhone, validPwd } from '@/utils/validate';
|
||||
import { checkExistence, CheckResult, signIn } from './service';
|
||||
import { checkExistence, CheckResult, signIn, signUp, sendCode } from './service';
|
||||
import { formatMessage } from 'umi-plugin-locale';
|
||||
|
||||
export enum PageStep {
|
||||
@@ -23,7 +23,12 @@ export interface CheckModelState {
|
||||
areacode: AreaCode | undefined, // 选中的地区
|
||||
phone: string;
|
||||
password: string;
|
||||
pwdConfirm: string;
|
||||
inviter: string;
|
||||
verifyCode: string;
|
||||
submitting: boolean;
|
||||
sendingCode: boolean;
|
||||
codeTimer: number;
|
||||
}
|
||||
|
||||
const model: Model = {
|
||||
@@ -36,7 +41,12 @@ const model: Model = {
|
||||
areacode: undefined,
|
||||
phone: '',
|
||||
password: '',
|
||||
pwdConfirm: '',
|
||||
inviter: '',
|
||||
verifyCode: '',
|
||||
submitting: false,
|
||||
sendingCode: false,
|
||||
codeTimer: -1,
|
||||
} as CheckModelState,
|
||||
|
||||
effects: {
|
||||
@@ -71,6 +81,15 @@ const model: Model = {
|
||||
}
|
||||
},
|
||||
|
||||
*timer({ payload }: any, { put }) {
|
||||
yield put({ type: 'onUpdateState', codeTimer: payload });
|
||||
yield delay(1000);
|
||||
const next = payload - 1;
|
||||
if (next >= 0) {
|
||||
yield put({ type: 'timer', payload: next });
|
||||
}
|
||||
},
|
||||
|
||||
*submitCheck(_, { put, call, select }) {
|
||||
const { areacode, phone } = yield select((state: any) => state.check);
|
||||
if (!areacode) return message.warn(formatMessage({ id: 'check.msgArea' }));
|
||||
@@ -97,26 +116,61 @@ const model: Model = {
|
||||
const { areacode, phone, password } = yield select((state: any) => state.check);
|
||||
if (!areacode) return message.warn(formatMessage({ id: 'check.msgArea' }));
|
||||
if (!validPhone(phone)) return message.warn(formatMessage({ id: 'check.msgPhone' }));
|
||||
if (!validPwd(password)) return message.warn(formatMessage({ id: 'check.msgPwd' }))
|
||||
if (!validPwd(password)) return message.warn(formatMessage({ id: 'check.msgPwd' }));
|
||||
|
||||
yield put({ type: 'onUpdateState', submitting: true });
|
||||
try {
|
||||
const token = yield call(signIn, areacode, phone, password);
|
||||
yield put({ type: 'user/updateToken', payload: token });
|
||||
yield delay(0);
|
||||
const user = yield call(getUserInfo, true);
|
||||
yield put({ type: 'user/updateUser', payload: user });
|
||||
} catch(e) {
|
||||
message.error(e.message);
|
||||
yield put({ type: 'user/logout' });
|
||||
} finally {
|
||||
yield put({ type: 'onUpdateState', submitting: false });
|
||||
}
|
||||
},
|
||||
|
||||
*submitRegister(_, { put }) {
|
||||
*submitRegister(_, { put, select, call }) {
|
||||
const { areacode, phone, password, verifyCode, inviter, pwdConfirm } = yield select((state: any) => state.check);
|
||||
if (!areacode) return message.warn(formatMessage({ id: 'check.msgArea' }));
|
||||
if (!validPhone(phone)) return message.warn(formatMessage({ id: 'check.msgPhone' }));
|
||||
if (!verifyCode) return message.warn(formatMessage({ id: 'check.msgCode' }));
|
||||
if (!validPwd(password)) return message.warn(formatMessage({ id: 'check.msgPwd' }));
|
||||
if (password !== pwdConfirm) return message.warn(formatMessage({ id: 'check.msgConfirm' }));
|
||||
// if (!inviter) return message.warn(formatMessage({ id: 'check.msgInviter' }));
|
||||
|
||||
yield put({ type: 'onUpdateState', submitting: true });
|
||||
yield delay(800);
|
||||
yield put({ type: 'onUpdateState', submitting: false });
|
||||
yield put({ type: 'onUpdateState', pageStep: PageStep.Check });
|
||||
try {
|
||||
const token = yield call(signUp, areacode, phone, password, verifyCode, inviter);
|
||||
yield put({ type: 'user/updateToken', payload: token });
|
||||
yield delay(0);
|
||||
const user = yield call(getUserInfo, true);
|
||||
yield put({ type: 'user/updateUser', payload: user });
|
||||
} catch(e) {
|
||||
message.error(e.message);
|
||||
yield put({ type: 'user/logout' });
|
||||
} finally {
|
||||
yield put({ type: 'onUpdateState', submitting: false });
|
||||
}
|
||||
},
|
||||
|
||||
*sendCode(_, { select, put, call }) {
|
||||
const { areacode, phone } = yield select((state: any) => state.check);
|
||||
if (!areacode) return message.warn(formatMessage({ id: 'check.msgArea' }));
|
||||
if (!validPhone(phone)) return message.warn(formatMessage({ id: 'check.msgPhone' }));
|
||||
|
||||
yield put({ type: 'onUpdateState', sendingCode: true });
|
||||
try {
|
||||
yield call(sendCode, areacode, phone);
|
||||
yield put({ type: 'timer', payload: 60 });
|
||||
} catch(e) {
|
||||
message.error(e.message);
|
||||
} finally {
|
||||
yield put({ type: 'onUpdateState', sendingCode: false });
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -4,30 +4,83 @@ import { connect, DispatchProp } from 'dva';
|
||||
import { formatMessage } from 'umi-plugin-locale';
|
||||
import { CheckModelState } from './model';
|
||||
|
||||
import styles from './style.less';
|
||||
|
||||
const RegisterPage: React.FC<DispatchProp & CheckModelState> = ({
|
||||
password,
|
||||
inviter,
|
||||
pwdConfirm,
|
||||
verifyCode,
|
||||
submitting,
|
||||
dispatch,
|
||||
codeTimer,
|
||||
sendingCode,
|
||||
}) => {
|
||||
let btnText;
|
||||
if (codeTimer < 0) {
|
||||
btnText = formatMessage({ id: 'check.getCode1' });
|
||||
} else if (codeTimer === 0) {
|
||||
btnText = formatMessage({ id: 'check.getCode3' });
|
||||
} else {
|
||||
btnText = formatMessage({ id: 'check.getCode2' }, { time: codeTimer })
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.register}>
|
||||
<Input.Group
|
||||
className="item"
|
||||
compact={true}
|
||||
size="large"
|
||||
>
|
||||
<Input
|
||||
style={{ width: '40%' }}
|
||||
placeholder={formatMessage({ id: 'common.codeHolder' })}
|
||||
value={verifyCode}
|
||||
onChange={e => dispatch({ type: 'check/onUpdateState', verifyCode: e.target.value })}
|
||||
/>
|
||||
<Button
|
||||
style={{ width: '60%' }}
|
||||
size="large"
|
||||
loading={sendingCode}
|
||||
disabled={codeTimer > 0}
|
||||
onClick={() => dispatch({ type: 'check/sendCode' })}
|
||||
>{btnText}</Button>
|
||||
</Input.Group>
|
||||
|
||||
<Input
|
||||
className="item"
|
||||
placeholder={formatMessage({ id: 'common.pwdHolder' })}
|
||||
placeholder={formatMessage({ id: 'check.setPwd' })}
|
||||
value={password}
|
||||
onChange={e => dispatch({ type: 'check/onUpdatePassword', payload: e.target.value })}
|
||||
size="large"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="item"
|
||||
placeholder={formatMessage({ id: 'check.confirmPwd' })}
|
||||
value={pwdConfirm}
|
||||
onChange={e => dispatch({ type: 'check/onUpdateState', pwdConfirm: e.target.value })}
|
||||
size="large"
|
||||
type="password"
|
||||
/>
|
||||
|
||||
<Input
|
||||
className="item"
|
||||
placeholder={formatMessage({ id: 'check.invite' })}
|
||||
value={inviter}
|
||||
onChange={e => dispatch({ type: 'check/onUpdateState', inviter: e.target.value })}
|
||||
size="large"
|
||||
/>
|
||||
|
||||
<Button
|
||||
className="item gradient"
|
||||
className="item gradient submit"
|
||||
type="primary"
|
||||
loading={submitting}
|
||||
onClick={() => dispatch({ type: 'check/submitRegister' })}
|
||||
size="large"
|
||||
>{formatMessage({ id: 'check.register' })}</Button>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,3 +28,33 @@ export async function signIn(areacode: AreaCode, phone: string, password: string
|
||||
}
|
||||
return data.token;
|
||||
}
|
||||
|
||||
export async function signUp(areacode: AreaCode, phone: string, password: string, code: string, inviter: string): Promise<string> {
|
||||
const { ok, msg, data } = await http.post(
|
||||
'/sign/up',
|
||||
{
|
||||
phone: encodePhone(areacode, phone),
|
||||
password,
|
||||
inviter,
|
||||
code,
|
||||
},
|
||||
);
|
||||
if (!ok || !data || !data.token) {
|
||||
throw Error(msg);
|
||||
}
|
||||
return data.token;
|
||||
}
|
||||
|
||||
export async function sendCode(areacode: AreaCode, phone: string) {
|
||||
const { ok, msg } = await http.post(
|
||||
'/sign/send',
|
||||
{
|
||||
phone: encodePhone(areacode, phone),
|
||||
type: 'signUp',
|
||||
},
|
||||
);
|
||||
if (ok) {
|
||||
return true;
|
||||
}
|
||||
throw Error(msg);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.ant-btn {
|
||||
.submit {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
@@ -54,3 +54,10 @@
|
||||
line-height: 30;
|
||||
line-height: 80vh;
|
||||
}
|
||||
|
||||
.register {
|
||||
height: 100%;
|
||||
padding-top: 160px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user