扫码登录页面

export default ({ dispatch, logined }: { dispatch: (action: Action) => void; logined: () => void }) => {
const [expired, setExpired] = useState(false);
const [qrinfo, setQrinfo] = useState('');
const [failed, setFailed] = useState(false);
return (
<div className={css.qrLogin}>
<div className={css.qrcode} onClick={reflush}>
{qrinfo && qrinfo !== '' && <Qrcode url={qrinfo} />}
{expired && (
<div className={css.expiredMask}>
{failed ? '二维码获取失败' : '二维码已失效'}
<div className={css.reflush} onClick={reflush}>
点击刷新
</div>
</div>
)}
</div>
</div>
);
};
账号密码登录页面

<div className={css.loginBtn} onClick={submit}>
登录
</div>
const userNameRef = createRef<HTMLInputElement>();
const userPWDRef = createRef<HTMLInputElement>();
const submit = useCallback(() => {
if (isEmpty(userNameRef) || isEmpty(userPWDRef)) {
Message.error(loginType === LoginType.SMS ? '手机号和验证码不能为空' : '账号密码不能为空');
return;
}
const vaildInfo = vaildInput(loginType, userNameRef, userPWDRef);
if (!vaildInfo.passed) {
Message.error(vaildInfo.result);
return;
}
const accountOrNumber = userNameRef.current?.value.trim();
const passwordOrSMSCode = userPWDRef.current?.value.trim();
dispatch(
loginType === LoginType.SMS
? {
type: LoginActions.QUICK_LOGIN,
payload: { phone: accountOrNumber, code: passwordOrSMSCode, logined }
}
: { type: LoginActions.LOGIN, payload: { nickName: accountOrNumber, password: passwordOrSMSCode, logined } }
);
}, [loginType, smsDelay]);
export function* smsLogin() {
while (true) {
const {
payload: { logined, ...payload }
} = yield take(LoginActionTypes.QUICK_LOGIN);
const result = yield call(request, { url: apiUrl.SMS_LOGIN, data: payload, method: 'POST' });
if (yield call(vaildCode, result)) {
yield call(saveUserToken, result);
yield call(logined);
} else {
yield call(showError, result.message ?? '验证码登录失败');
}
}
}
jest
it('手机号验证码登录', () => {
expect(smsLoginSaga.next().value).toEqual(take(LoginActionTypes.QUICK_LOGIN));
expect(smsLoginSaga.next({ payload: { logined: console.log } }).value).toEqual(
call(request, { url: apiUrl.SMS_LOGIN, data: {}, method: 'POST' })
);
expect(smsLoginSaga.next({ code: 0 }).value).toEqual(call(vaildCode, { code: 0 }));
expect(smsLoginSaga.clone().next(false).value).toEqual(call(showError, expect.any(String)));
expect(smsLoginSaga.next(true).value).toEqual(call(saveUserToken, expect.any(Object)));
expect(smsLoginSaga.next().value).toEqual(call(console.log));
});
点击刷新
export function* quickLogin() {
while (true) {
const {
payload: { qrcode, logined, failed }
} = yield take(LoginActionTypes.QRCODE_CREATE);
const { result, dispose } = yield race({
result: call(request, { url: apiUrl.LOGIN_QRCODE_CREATE }),
dispose: take(LoginActionTypes.QRCODE_DISPOSE)
});
if (dispose) {
continue;
}
if (yield call(vaildCode, result)) {
if (result.url) {
yield call(qrcode, result.url);
const checkTask = yield fork(checkQrcode, result.qr_code, logined, failed);
yield put({
type: LoginActionTypes.SET_ERCODE,
payload: {
code: result.qr_code
}
});
yield race({ expired: take(LoginActionTypes.QRCODE_EXPIRED), dispose: take(LoginActionTypes.QRCODE_DISPOSE) });
yield call(cancelAll, [checkTask]);
} else {
yield call(failed);
}
} else {
yield call(failed);
}
}
}
const reflush = useCallback(() => {
setExpired(false);
dispatch({ type: LoginActions.QRCODE_CREATE, payload: createOption });
}, [expired, failed]);
export function* quickLogin() {
while (true) {
const {
payload: { qrcode, logined, failed }
} = yield take(LoginActionTypes.QRCODE_CREATE);
const { result, dispose } = yield race({
result: call(request, { url: apiUrl.LOGIN_QRCODE_CREATE }),
dispose: take(LoginActionTypes.QRCODE_DISPOSE)
});
if (dispose) {
continue;
}
if (yield call(vaildCode, result)) {
if (result.url) {
yield call(qrcode, result.url);
const checkTask = yield fork(checkQrcode, result.qr_code, logined, failed);
yield put({
type: LoginActionTypes.SET_ERCODE,
payload: {
code: result.qr_code
}
});
yield race({ expired: take(LoginActionTypes.QRCODE_EXPIRED), dispose: take(LoginActionTypes.QRCODE_DISPOSE) });
yield call(cancelAll, [checkTask]);
} else {
yield call(failed);
}
} else {
yield call(failed);
}
}
}
获取二维码
const expiredTask = useRef<any>();
const getQrcodeHandler = useCallback(
(url: string) => {
setExpired(false);
setFailed(false);
setQrinfo(url);
clearTimeout(expiredTask.current);
expiredTask.current = setTimeout(() => {
setExpired(true);
dispatch({ type: LoginActions.QRCODE_EXPIRED, payload: {} });
}, 600 * 1000);
},
[expired, dispatch]
);
const getQrcodeFailure = useCallback(() => {
setExpired(true);
setFailed(true);
dispatch({ type: LoginActions.QRCODE_EXPIRED, payload: {} });
}, [failed]);
const createOption = useMemo(() => {
return { qrcode: getQrcodeHandler, logined, failed: getQrcodeFailure };
}, [getQrcodeHandler, getQrcodeFailure, logined]);
useEffect(() => {
if (qrinfo === '') {
dispatch({ type: LoginActions.QRCODE_CREATE, payload: createOption });
}
return () => {
clearTimeout(expiredTask.current);
dispatch({ type: LoginActions.QRCODE_DISPOSE, payload: {} });
};
}, []);