165 lines
5.1 KiB
TypeScript
165 lines
5.1 KiB
TypeScript
import dayjs from 'dayjs';
|
|
import { LOCAL_STORAGE_KEYS } from '../../../config/constants';
|
|
import { PwdConfig } from '../../../entities/Passport';
|
|
import { EntityDict } from 'oak-domain/lib/types';
|
|
import { encryptPasswordSha1 } from '../../../utils/password';
|
|
const SEND_KEY = LOCAL_STORAGE_KEYS.captchaSendAt;
|
|
const SEND_CAPTCHA_LATENCY = process.env.NODE_ENV === 'development' ? 10 : 60;
|
|
|
|
export default OakComponent({
|
|
isList: false,
|
|
entity: 'user',
|
|
projection: {
|
|
id: 1,
|
|
name: 1,
|
|
nickname: 1,
|
|
mobile$user: {
|
|
$entity: 'mobile',
|
|
data: {
|
|
id: 1,
|
|
mobile: 1,
|
|
},
|
|
filter: {
|
|
ableState: 'enabled'
|
|
}
|
|
}
|
|
},
|
|
formData: function ({ data: user, features, props }) {
|
|
let counter = 0;
|
|
const { lastSendAt } = this.state;
|
|
if (typeof lastSendAt === 'number') {
|
|
counter = Math.max(
|
|
SEND_CAPTCHA_LATENCY - Math.ceil((Date.now() - lastSendAt) / 1000),
|
|
0
|
|
);
|
|
if (counter > 0) {
|
|
(this as any).counterHandler = setTimeout(
|
|
() => this.reRender(),
|
|
1000
|
|
);
|
|
} else if ((this as any).counterHandler) {
|
|
clearTimeout((this as any).counterHandler);
|
|
(this as any).counterHandler = undefined;
|
|
}
|
|
}
|
|
return {
|
|
user,
|
|
counter,
|
|
mobile: user?.mobile$user?.[0]?.mobile
|
|
};
|
|
},
|
|
data: {
|
|
channels: [] as string[],
|
|
failTimes: 0,
|
|
captcha: '',
|
|
lastSendAt: undefined as number | undefined,
|
|
mode: 'all',
|
|
pwdMin: 8,
|
|
pwdMax: 24,
|
|
needVerify: false,
|
|
regexs: [] as string[],
|
|
tip: '',
|
|
},
|
|
lifetimes: {
|
|
async ready() {
|
|
const lastSendAt = await this.load(SEND_KEY);
|
|
const system = this.features.application.getApplication().system;
|
|
const passwordConfig = system?.config.Password;
|
|
const mode = passwordConfig?.mode ?? 'all';
|
|
const pwdMin = passwordConfig?.min ?? 8;
|
|
const pwdMax = passwordConfig?.max ?? 24;
|
|
const needVerify = !!passwordConfig?.verify;
|
|
const regexs = (passwordConfig?.regexs && passwordConfig?.regexs.length > 0) ? passwordConfig?.regexs : [];
|
|
const tip = passwordConfig?.tip ?? '';
|
|
this.setState({
|
|
mode,
|
|
pwdMin,
|
|
pwdMax,
|
|
needVerify,
|
|
regexs,
|
|
tip,
|
|
})
|
|
if (lastSendAt) {
|
|
this.setState({
|
|
lastSendAt,
|
|
}, () => this.reRender())
|
|
}
|
|
}
|
|
},
|
|
methods: {
|
|
async sendCaptcha(mobile: string) {
|
|
try {
|
|
const result = await this.features.token.sendCaptcha('mobile', mobile, 'changePassword');
|
|
// 显示返回消息
|
|
this.setMessage({
|
|
type: 'success',
|
|
content: result,
|
|
});
|
|
const lastSendAt = Date.now();
|
|
this.save(SEND_KEY, lastSendAt);
|
|
this.setState({
|
|
lastSendAt,
|
|
}, () => this.reRender())
|
|
} catch (err) {
|
|
this.setMessage({
|
|
type: 'error',
|
|
content: (err as Error).message,
|
|
});
|
|
}
|
|
},
|
|
setCaptcha(value: string) {
|
|
this.setState(
|
|
{
|
|
captcha: value,
|
|
}
|
|
)
|
|
},
|
|
setMobile(value: string) {
|
|
this.setState(
|
|
{
|
|
mobile: value,
|
|
}
|
|
)
|
|
},
|
|
async onConfirmByMobile(mobile: string, captcha: string, newPassword: string) {
|
|
const { mode } = this.state;
|
|
const userId = this.props.oakId as string;
|
|
const { user } = this.state;
|
|
let newPwd = newPassword;
|
|
if (mode === 'sha1') {
|
|
newPwd = encryptPasswordSha1(newPassword);
|
|
}
|
|
const { result } = await this.features.cache.exec('updateUserPassword', {
|
|
userId,
|
|
mobile,
|
|
captcha,
|
|
newPassword: newPwd,
|
|
});
|
|
const { result: resultMessage, times } = result;
|
|
if (resultMessage === 'success') {
|
|
this.setMessage(
|
|
{
|
|
type: 'success',
|
|
content: '修改密码成功'
|
|
}
|
|
)
|
|
this.navigateBack();
|
|
} else {
|
|
if (times) {
|
|
this.setState(
|
|
{
|
|
failTimes: times,
|
|
}
|
|
)
|
|
}
|
|
this.setMessage(
|
|
{
|
|
type: 'error',
|
|
content: resultMessage
|
|
}
|
|
)
|
|
}
|
|
}
|
|
},
|
|
});
|