修改手机号

This commit is contained in:
saplf
2019-09-06 15:39:28 +08:00
parent 53509b8aa2
commit b700f76d27
8 changed files with 324 additions and 1 deletions

View File

@@ -21,6 +21,7 @@ export default {
'common.modify': 'Modify',
'common.copied': '复制成功',
'common.prompt': 'Prompt',
'common.iknow': 'I know',
'check.login': 'Sign In',
'check.register': 'Sign Up',
@@ -124,6 +125,12 @@ export default {
'invite.step2': '注册',
'invite.step3': '领取奖金',
'chphone.title': '更换手机号',
'chphone.new': '请输入您的新手机号',
'chphone.code': '请输入手机验证码',
'chphone.btn': '更换',
'chphone.success': '您已成功更换了手机号,下次登录请使用新手机号!',
'fundpwd.title': '修改资金密码',
'fundpwd.origin': '验证原资金密码',
'fundpwd.new': '设置新的资金密码',

View File

@@ -21,6 +21,7 @@ export default {
'common.modify': '修改',
'common.copied': '复制成功',
'common.prompt': '提示',
'common.iknow': '我知道了',
'check.login': '登录',
'check.register': '注册',
@@ -124,6 +125,12 @@ export default {
'invite.step2': '注册',
'invite.step3': '领取奖金',
'chphone.title': '更换手机号',
'chphone.new': '请输入您的新手机号',
'chphone.code': '请输入手机验证码',
'chphone.btn': '更换',
'chphone.success': '您已成功更换了手机号,下次登录请使用新手机号!',
'fundpwd.title': '修改资金密码',
'fundpwd.origin': '验证原资金密码',
'fundpwd.new': '设置新的资金密码',

View File

@@ -73,6 +73,7 @@ const AccountPage: React.FC<DispatchProp & UserModelState & AccountModelState> =
className="group"
title="account.phone"
message={user.phone}
onClick={() => dispatch(routerRedux.push('/chphone'))}
/>
<AccountItem
className="group"

114
src/pages/chphone/index.tsx Normal file
View File

@@ -0,0 +1,114 @@
/**
* Title: 邀请新人
* Routes:
* - ./src/pages/routes
*/
import React, { useEffect, useState } from 'react';
import { connect, DispatchProp } from 'dva';
import { Spin, Button, message, Input } from 'antd';
import { formatMessage } from 'umi-plugin-locale';
import { ChphoneModelState } from './model';
import Header from '@/components/Header';
import AreaSelection from '@/components/AreaSelection';
import styles from './style.less';
import { UserModelState } from '@/models/user';
import { PageState } from '@/types/common';
const ChphonePage: React.FC<DispatchProp & ChphoneModelState & UserModelState> = ({
dispatch,
pageState,
areacode,
areacodes,
phone,
code,
submitting,
codeTimer,
sendingCode,
}) => {
useEffect(() => {
dispatch({ type: 'chphone/load' });
}, []);
let body;
if (pageState === PageState.Pending) {
body = (
<Spin className={styles.none} />
);
} else if (pageState === PageState.Failure) {
body = (
<div className={styles.none}>{formatMessage({ id: 'common.loadError' })}</div>
);
} else if (pageState === PageState.Success) {
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 })
}
body = (
<>
<AreaSelection
className={styles.input}
areacode={areacode}
areacodes={areacodes}
onChange={areacode => dispatch({ type: 'chphone/onUpdateState', areacode })}
size="large"
/>
<Input
className={styles.input}
value={phone}
onChange={e => dispatch({ type: 'chphone/onUpdatePhone', payload: e.target.value })}
placeholder={formatMessage({ id: 'chphone.new' })}
size="large"
type="tel"
/>
<Input.Group
className={styles.input}
compact={true}
size="large"
>
<Input
style={{ width: '40%' }}
placeholder={formatMessage({ id: 'chphone.code' })}
value={code}
onChange={e => dispatch({ type: 'chphone/onUpdateState', code: e.target.value })}
/>
<Button
style={{ width: '60%' }}
size="large"
loading={sendingCode}
disabled={codeTimer > 0}
onClick={() => dispatch({ type: 'chphone/sendCode' })}
>{btnText}</Button>
</Input.Group>
<Button
className={styles.input}
type="primary"
size="large"
loading={submitting}
onClick={() => dispatch({ type: 'chphone/submit' })}
>{formatMessage({ id: 'chphone.btn' })}</Button>
</>
);
}
return (
<div className={styles.container}>
<Header
className="header"
title={formatMessage({ id: 'chphone.title' })}
/>
<div className={styles.body}>
{body}
</div>
</div>
);
};
export default connect(
({ chphone }: any) => ({ ...chphone }),
)(ChphonePage);

138
src/pages/chphone/model.ts Normal file
View File

@@ -0,0 +1,138 @@
import { Model, routerRedux } from "dva";
import _ from 'lodash';
import { delay } from 'dva/saga';
import { PageState, AreaCode, AreaCodes } from '@/types/common';
import { getAreaCodes } from '@/services/common';
import { message, Modal } from 'antd';
import { formatMessage } from 'umi-plugin-locale';
import { validPwd, validPhone, validPhoneInput } from '@/utils/validate';
import { changePhone, sendCode } from './service';
import { dispatch } from '@/utils/utils';
export interface ChphoneModelState {
pageState: PageState;
areacodes: AreaCodes,
areacode: AreaCode | undefined, // 选中的地区
phone: string;
code: string;
submitting: boolean;
sendingCode: boolean;
codeTimer: number;
}
const initState: ChphoneModelState = {
pageState: PageState.Pending,
areacodes: [],
areacode: undefined,
phone: '',
code: '',
submitting: false,
sendingCode: false,
codeTimer: -1,
};
const model: Model = {
namespace: 'chphone',
state: initState,
effects: {
*load(_, { put, call }) {
yield put({ type: 'onUpdateState', pageState: PageState.Pending });
try {
const areacodes = yield call(getAreaCodes);
yield put({
type: 'onUpdateState',
pageState: PageState.Success,
areacodes,
areacode: areacodes[0],
phone: '',
code: '',
submitting: false,
sendingCode: false,
codeTimer: -1,
});
} catch (e) {
yield put({
type: 'onUpdateState',
pageState: PageState.Failure,
});
}
},
*submit(_, { put, call, select }) {
const {
areacode,
phone,
code,
submitting,
} = (yield select((state: any) => state.chphone)) as ChphoneModelState;
if (submitting) return;
if (!areacode) return message.warn(formatMessage({ id: 'check.msgArea' }));
if (!validPhone(phone)) return message.warn(formatMessage({ id: 'check.msgPhone' }));
if (!code) return message.warn(formatMessage({ id: 'check.msgCode' }));
yield put({ type: 'onUpdateState', submitting: true });
try {
yield call(changePhone, phone, code);
yield put({ type: 'user/updateUser', payload: { phone } });
Modal.success({
okText: formatMessage({ id: 'common.iknow' }),
title: formatMessage({ id: 'common.prompt' }),
content: formatMessage({ id: 'chphone.success' }),
onOk: () => dispatch(routerRedux.goBack()),
maskClosable: false,
});
} catch (e) {
message.error(e.message);
} finally {
yield put({ type: 'onUpdateState', submitting: false })
}
},
*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 });
}
},
*sendCode(_, { select, put, call }) {
const { areacode, phone } = yield select((state: any) => state.chphone);
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 });
}
},
},
reducers: {
onUpdateState(state, payload) {
return {
...state,
...payload,
};
},
onUpdatePhone(state, { payload } : any) {
const phone = validPhoneInput(payload) ? payload : state.phone;
return {
...state,
phone,
};
},
},
};
export default model;

View File

@@ -0,0 +1,26 @@
import http from '@/utils/http';
import { encodePhone } from '@/utils/transform';
import { AreaCode } from '@/types/common';
export async function changePhone(phone: string, code: string) {
const { ok, msg } = await http.post('/user/chphone', {
phone,
code,
});
if (ok) return;
throw Error(msg);
}
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);
}

View File

@@ -0,0 +1,30 @@
@import '../../global.less';
.container {
height: 100%;
background: white;
position: relative;
display: flex;
flex-direction: column;
}
.body {
flex-grow: 1;
overflow-x: hidden;
overflow-y: auto;
display: flex;
flex-direction: column;
align-items: stretch;
}
.none {
text-align: center;
width: 100%;
padding-top: 40%;
}
.input {
margin: 10px 20px;
width: auto;
}

View File

@@ -68,7 +68,7 @@ const model: Model = {
if (confirm !== newPwd) return message.warn(formatMessage({ id: 'check.msgConfirm' }));
yield put({ type: 'onUpdateState', submitting: true });
try {
yield call(changeFundPwd, newPwd, origin);
yield call(changeFundPwd, newPwd, originVisible ? undefined : origin);
yield put(routerRedux.goBack());
message.success(formatMessage({ id: 'fundpwd.success' }));
} catch (e) {