update password
This commit is contained in:
parent
f65a72821b
commit
7a56680935
@ -33,6 +33,10 @@
|
|||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"Bill Detail": "Bill Detail",
|
"Bill Detail": "Bill Detail",
|
||||||
"Pay": "Pay"
|
"Pay": "Pay",
|
||||||
|
"Update Password": "Update Password",
|
||||||
|
"Update password failed": "Update password failed",
|
||||||
|
"Update password succseful": "Update password succseful",
|
||||||
|
"Old password is error": "Old password is error"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,10 @@
|
|||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"Bill Detail": "账单详情",
|
"Bill Detail": "账单详情",
|
||||||
"Pay": "充值"
|
"Pay": "充值",
|
||||||
|
"Update Password": "修改密码",
|
||||||
|
"Update password failed": "修改密码异常",
|
||||||
|
"Update password succseful": "修改密码成功",
|
||||||
|
"Old password is error": "旧密码错误"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ export const sendAuthCode = (data: {
|
|||||||
googleToken: string;
|
googleToken: string;
|
||||||
}) => POST('/user/sendAuthCode', data);
|
}) => POST('/user/sendAuthCode', data);
|
||||||
|
|
||||||
export const getTokenLogin = () => GET<UserType>('/user/tokenLogin');
|
export const getTokenLogin = () => GET<UserType>('/user/account/tokenLogin');
|
||||||
|
|
||||||
export const postRegister = ({
|
export const postRegister = ({
|
||||||
username,
|
username,
|
||||||
@ -25,7 +25,7 @@ export const postRegister = ({
|
|||||||
password: string;
|
password: string;
|
||||||
inviterId: string;
|
inviterId: string;
|
||||||
}) =>
|
}) =>
|
||||||
POST<ResLogin>('/user/register', {
|
POST<ResLogin>('/user/account/register', {
|
||||||
username,
|
username,
|
||||||
code,
|
code,
|
||||||
inviterId,
|
inviterId,
|
||||||
@ -41,21 +41,27 @@ export const postFindPassword = ({
|
|||||||
code: string;
|
code: string;
|
||||||
password: string;
|
password: string;
|
||||||
}) =>
|
}) =>
|
||||||
POST<ResLogin>('/user/updatePasswordByCode', {
|
POST<ResLogin>('/user/account/updatePasswordByCode', {
|
||||||
username,
|
username,
|
||||||
code,
|
code,
|
||||||
password: createHashPassword(password)
|
password: createHashPassword(password)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const updatePasswordByOld = ({ oldPsw, newPsw }: { oldPsw: string; newPsw: string }) =>
|
||||||
|
POST('/user/account/updatePasswordByOld', {
|
||||||
|
oldPsw: createHashPassword(oldPsw),
|
||||||
|
newPsw: createHashPassword(newPsw)
|
||||||
|
});
|
||||||
|
|
||||||
export const postLogin = ({ username, password }: { username: string; password: string }) =>
|
export const postLogin = ({ username, password }: { username: string; password: string }) =>
|
||||||
POST<ResLogin>('/user/loginByPassword', {
|
POST<ResLogin>('/user/account/loginByPassword', {
|
||||||
username,
|
username,
|
||||||
password: createHashPassword(password)
|
password: createHashPassword(password)
|
||||||
});
|
});
|
||||||
|
|
||||||
export const loginOut = () => GET('/user/loginout');
|
export const loginOut = () => GET('/user/account/loginout');
|
||||||
|
|
||||||
export const putUserInfo = (data: UserUpdateParams) => PUT('/user/update', data);
|
export const putUserInfo = (data: UserUpdateParams) => PUT('/user/account/update', data);
|
||||||
|
|
||||||
export const getUserBills = (data: RequestPaging) =>
|
export const getUserBills = (data: RequestPaging) =>
|
||||||
POST<PagingData<UserBillType>>(`/user/getBill`, data);
|
POST<PagingData<UserBillType>>(`/user/getBill`, data);
|
||||||
|
|||||||
@ -2,14 +2,16 @@ import { useToast } from '@/hooks/useToast';
|
|||||||
import { useMutation } from '@tanstack/react-query';
|
import { useMutation } from '@tanstack/react-query';
|
||||||
import type { UseMutationOptions } from '@tanstack/react-query';
|
import type { UseMutationOptions } from '@tanstack/react-query';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
interface Props extends UseMutationOptions<any, any, any, any> {
|
interface Props extends UseMutationOptions<any, any, any, any> {
|
||||||
successToast?: string;
|
successToast?: string | null;
|
||||||
errorToast?: string;
|
errorToast?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...props }: Props) => {
|
export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...props }: Props) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
|
const { t } = useTranslation();
|
||||||
const mutation = useMutation<unknown, unknown, any, unknown>({
|
const mutation = useMutation<unknown, unknown, any, unknown>({
|
||||||
...props,
|
...props,
|
||||||
onSuccess(res, variables: void, context: unknown) {
|
onSuccess(res, variables: void, context: unknown) {
|
||||||
@ -24,7 +26,7 @@ export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...pr
|
|||||||
onError?.(err, variables, context);
|
onError?.(err, variables, context);
|
||||||
errorToast &&
|
errorToast &&
|
||||||
toast({
|
toast({
|
||||||
title: getErrText(err, errorToast),
|
title: t(getErrText(err, errorToast)),
|
||||||
status: 'error'
|
status: 'error'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import { Box, Flex, Button, useDisclosure } from '@chakra-ui/react';
|
import { Box, Flex, Button, useDisclosure, useTheme, ModalBody } from '@chakra-ui/react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
import { UserUpdateParams } from '@/types/user';
|
import { UserUpdateParams } from '@/types/user';
|
||||||
import { putUserInfo } from '@/api/user';
|
import { putUserInfo } from '@/api/user';
|
||||||
@ -7,35 +7,48 @@ import { useToast } from '@/hooks/useToast';
|
|||||||
import { useGlobalStore } from '@/store/global';
|
import { useGlobalStore } from '@/store/global';
|
||||||
import { useUserStore } from '@/store/user';
|
import { useUserStore } from '@/store/user';
|
||||||
import { UserType } from '@/types/user';
|
import { UserType } from '@/types/user';
|
||||||
import { useRouter } from 'next/router';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import dynamic from 'next/dynamic';
|
import dynamic from 'next/dynamic';
|
||||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||||
import { compressImg } from '@/utils/file';
|
import { compressImg } from '@/utils/file';
|
||||||
import { getErrText } from '@/utils/tools';
|
import { getErrText } from '@/utils/tools';
|
||||||
import { feConfigs } from '@/store/static';
|
import { feConfigs } from '@/store/static';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import Loading from '@/components/Loading';
|
import Loading from '@/components/Loading';
|
||||||
import Avatar from '@/components/Avatar';
|
import Avatar from '@/components/Avatar';
|
||||||
|
import MyIcon from '@/components/Icon';
|
||||||
|
import MyTooltip from '@/components/MyTooltip';
|
||||||
|
|
||||||
const PayModal = dynamic(() => import('./PayModal'), {
|
const PayModal = dynamic(() => import('./PayModal'), {
|
||||||
loading: () => <Loading fixed={false} />,
|
loading: () => <Loading fixed={false} />,
|
||||||
ssr: false
|
ssr: false
|
||||||
});
|
});
|
||||||
|
const UpdatePswModal = dynamic(() => import('./UpdatePswModal'), {
|
||||||
|
loading: () => <Loading fixed={false} />,
|
||||||
|
ssr: false
|
||||||
|
});
|
||||||
|
|
||||||
const UserInfo = () => {
|
const UserInfo = () => {
|
||||||
const router = useRouter();
|
const theme = useTheme();
|
||||||
|
const { t } = useTranslation();
|
||||||
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
|
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
|
||||||
const { setLoading } = useGlobalStore();
|
const { setLoading } = useGlobalStore();
|
||||||
const { reset } = useForm<UserUpdateParams>({
|
const { reset, register } = useForm<UserUpdateParams>({
|
||||||
defaultValues: userInfo as UserType
|
defaultValues: userInfo as UserType
|
||||||
});
|
});
|
||||||
|
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const {
|
const {
|
||||||
isOpen: isOpenPayModal,
|
isOpen: isOpenPayModal,
|
||||||
onClose: onClosePayModal,
|
onClose: onClosePayModal,
|
||||||
onOpen: onOpenPayModal
|
onOpen: onOpenPayModal
|
||||||
} = useDisclosure();
|
} = useDisclosure();
|
||||||
|
const {
|
||||||
|
isOpen: isOpenUpdatePsw,
|
||||||
|
onClose: onCloseUpdatePsw,
|
||||||
|
onOpen: onOpenUpdatePsw
|
||||||
|
} = useDisclosure();
|
||||||
const { File, onOpen: onOpenSelectFile } = useSelectFile({
|
const { File, onOpen: onOpenSelectFile } = useSelectFile({
|
||||||
fileType: '.jpg,.png',
|
fileType: '.jpg,.png',
|
||||||
multiple: false
|
multiple: false
|
||||||
@ -98,41 +111,68 @@ const UserInfo = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
return (
|
return (
|
||||||
<Flex flexDirection={'column'} alignItems={'center'} py={[0, 8]} fontSize={['lg', 'xl']}>
|
<Box display={['block', 'flex']} py={[2, 10]} justifyContent={'center'} fontSize={['lg', 'xl']}>
|
||||||
<Flex mt={6} alignItems={'center'} w={'260px'}>
|
<Flex
|
||||||
<Box flex={'0 0 50px'}>头像:</Box>
|
flexDirection={'column'}
|
||||||
<Box flex={1} pl={10}>
|
alignItems={'center'}
|
||||||
<Avatar
|
cursor={'pointer'}
|
||||||
src={userInfo?.avatar}
|
onClick={onOpenSelectFile}
|
||||||
w={['34px', '44px']}
|
>
|
||||||
h={['34px', '44px']}
|
<MyTooltip label={'更换头像'}>
|
||||||
cursor={'pointer'}
|
<Box
|
||||||
title={'点击切换头像'}
|
w={['44px', '54px']}
|
||||||
onClick={onOpenSelectFile}
|
h={['44px', '54px']}
|
||||||
/>
|
borderRadius={'50%'}
|
||||||
</Box>
|
border={theme.borders.base}
|
||||||
|
boxShadow={'0 0 5px rgba(0,0,0,0.1)'}
|
||||||
|
mb={2}
|
||||||
|
>
|
||||||
|
<Avatar src={userInfo?.avatar} w={'100%'} h={'100%'} />
|
||||||
|
</Box>
|
||||||
|
</MyTooltip>
|
||||||
|
|
||||||
|
<Flex alignItems={'center'} fontSize={'sm'} color={'myGray.600'}>
|
||||||
|
<MyIcon mr={1} name={'edit'} w={'14px'} />
|
||||||
|
更换
|
||||||
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Flex mt={6} alignItems={'center'} w={'260px'}>
|
<Box
|
||||||
<Box flex={'0 0 50px'}>账号:</Box>
|
display={['flex', 'block']}
|
||||||
<Box>{userInfo?.username}</Box>
|
flexDirection={'column'}
|
||||||
</Flex>
|
alignItems={'center'}
|
||||||
{feConfigs?.show_userDetail && (
|
ml={[0, 10]}
|
||||||
<Box mt={6} w={'260px'} whiteSpace={'nowrap'}>
|
mt={[6, 0]}
|
||||||
<Flex alignItems={'center'}>
|
>
|
||||||
<Box flex={'0 0 50px'}>余额:</Box>
|
<Flex alignItems={'center'} w={['85%', '300px']}>
|
||||||
<Box>
|
<Box flex={'0 0 50px'}>账号:</Box>
|
||||||
<strong>{userInfo?.balance.toFixed(3)}</strong> 元
|
<Box flex={1}>{userInfo?.username}</Box>
|
||||||
</Box>
|
</Flex>
|
||||||
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
|
<Flex mt={6} alignItems={'center'} w={['85%', '300px']}>
|
||||||
充值
|
<Box flex={'0 0 50px'}>密码:</Box>
|
||||||
</Button>
|
<Box flex={1}>*****</Box>
|
||||||
</Flex>
|
<Button size={['sm', 'md']} variant={'base'} ml={5} onClick={onOpenUpdatePsw}>
|
||||||
</Box>
|
变更
|
||||||
)}
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
{feConfigs?.show_userDetail && (
|
||||||
|
<Box mt={6} whiteSpace={'nowrap'} w={['85%', '300px']}>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 50px'}>余额:</Box>
|
||||||
|
<Box flex={1}>
|
||||||
|
<strong>{userInfo?.balance.toFixed(3)}</strong> 元
|
||||||
|
</Box>
|
||||||
|
<Button size={['sm', 'md']} ml={5} onClick={onOpenPayModal}>
|
||||||
|
充值
|
||||||
|
</Button>
|
||||||
|
</Flex>
|
||||||
|
</Box>
|
||||||
|
)}
|
||||||
|
</Box>
|
||||||
|
|
||||||
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
|
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
|
||||||
|
{isOpenUpdatePsw && <UpdatePswModal onClose={onCloseUpdatePsw} />}
|
||||||
<File onSelect={onSelectFile} />
|
<File onSelect={onSelectFile} />
|
||||||
</Flex>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
58
client/src/pages/account/components/UpdatePswModal.tsx
Normal file
58
client/src/pages/account/components/UpdatePswModal.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ModalBody, Box, Flex, Input, ModalFooter, Button } from '@chakra-ui/react';
|
||||||
|
import MyModal from '@/components/MyModal';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { useRequest } from '@/hooks/useRequest';
|
||||||
|
import { updatePasswordByOld } from '@/api/user';
|
||||||
|
|
||||||
|
const UpdatePswModal = ({ onClose }: { onClose: () => void }) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { register, handleSubmit } = useForm({
|
||||||
|
defaultValues: {
|
||||||
|
oldPsw: '',
|
||||||
|
newPsw: '',
|
||||||
|
confirmPsw: ''
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const { mutate: onSubmit, isLoading } = useRequest({
|
||||||
|
mutationFn: (data) => {
|
||||||
|
return updatePasswordByOld(data);
|
||||||
|
},
|
||||||
|
onSuccess() {
|
||||||
|
onClose();
|
||||||
|
},
|
||||||
|
successToast: t('user.Update password succseful'),
|
||||||
|
errorToast: t('user.Update password failed')
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MyModal isOpen onClose={onClose} title={t('user.Update Password')}>
|
||||||
|
<ModalBody>
|
||||||
|
<Flex alignItems={'center'}>
|
||||||
|
<Box flex={'0 0 70px'}>旧密码:</Box>
|
||||||
|
<Input flex={1} type={'password'} {...register('oldPsw', { required: true })}></Input>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={5}>
|
||||||
|
<Box flex={'0 0 70px'}>新密码:</Box>
|
||||||
|
<Input flex={1} type={'password'} {...register('newPsw', { required: true })}></Input>
|
||||||
|
</Flex>
|
||||||
|
<Flex alignItems={'center'} mt={5}>
|
||||||
|
<Box flex={'0 0 70px'}>确认密码:</Box>
|
||||||
|
<Input flex={1} type={'password'} {...register('confirmPsw', { required: true })}></Input>
|
||||||
|
</Flex>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<Button mr={3} variant={'base'} onClick={onClose}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button isLoading={isLoading} onClick={handleSubmit((data) => onSubmit(data))}>
|
||||||
|
确认
|
||||||
|
</Button>
|
||||||
|
</ModalFooter>
|
||||||
|
</MyModal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UpdatePswModal;
|
||||||
49
client/src/pages/api/user/account/updatePasswordByOld.ts
Normal file
49
client/src/pages/api/user/account/updatePasswordByOld.ts
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import { jsonRes } from '@/service/response';
|
||||||
|
import { User } from '@/service/models/user';
|
||||||
|
import { AuthCode } from '@/service/models/authCode';
|
||||||
|
import { connectToDatabase } from '@/service/mongo';
|
||||||
|
import { UserAuthTypeEnum } from '@/constants/common';
|
||||||
|
import { setCookie } from '@/service/utils/tools';
|
||||||
|
import { authUser } from '@/service/utils/auth';
|
||||||
|
|
||||||
|
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
|
||||||
|
try {
|
||||||
|
const { oldPsw, newPsw } = req.body as { oldPsw: string; newPsw: string };
|
||||||
|
|
||||||
|
if (!oldPsw || !newPsw) {
|
||||||
|
throw new Error('Params is missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
await connectToDatabase();
|
||||||
|
|
||||||
|
const { userId } = await authUser({ req, authToken: true });
|
||||||
|
|
||||||
|
// auth old password
|
||||||
|
const user = await User.findOne({
|
||||||
|
_id: userId,
|
||||||
|
password: oldPsw
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
throw new Error('user.Old password is error');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新对应的记录
|
||||||
|
await User.findByIdAndUpdate(userId, {
|
||||||
|
password: newPsw
|
||||||
|
});
|
||||||
|
|
||||||
|
jsonRes(res, {
|
||||||
|
data: {
|
||||||
|
user
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
jsonRes(res, {
|
||||||
|
code: 500,
|
||||||
|
error: err
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -74,7 +74,7 @@ const Share = ({ appId }: { appId: string }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box position={'relative'} pt={[0, 5, 8]} px={[5, 8]} minH={'50vh'}>
|
<Box position={'relative'} pt={[3, 5, 8]} px={[5, 8]} minH={'50vh'}>
|
||||||
<Flex justifyContent={'space-between'}>
|
<Flex justifyContent={'space-between'}>
|
||||||
<Box fontWeight={'bold'}>
|
<Box fontWeight={'bold'}>
|
||||||
免登录窗口
|
免登录窗口
|
||||||
@ -222,7 +222,7 @@ const OutLink = ({ appId }: { appId: string }) => {
|
|||||||
</Box>
|
</Box>
|
||||||
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
||||||
<MyRadio
|
<MyRadio
|
||||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2, 350px)']}
|
gridTemplateColumns={['repeat(1,1fr)', 'repeat(auto-fill, minmax(0, 360px))']}
|
||||||
iconSize={'20px'}
|
iconSize={'20px'}
|
||||||
list={[
|
list={[
|
||||||
{
|
{
|
||||||
@ -230,13 +230,13 @@ const OutLink = ({ appId }: { appId: string }) => {
|
|||||||
title: '免登录窗口',
|
title: '免登录窗口',
|
||||||
desc: '分享链接给其他用户,无需登录即可直接进行使用',
|
desc: '分享链接给其他用户,无需登录即可直接进行使用',
|
||||||
value: LinkTypeEnum.share
|
value: LinkTypeEnum.share
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'outlink_iframe',
|
||||||
|
title: '网页嵌入',
|
||||||
|
desc: '嵌入到已有网页中,右下角会生成对话按键',
|
||||||
|
value: LinkTypeEnum.iframe
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// icon: 'outlink_iframe',
|
|
||||||
// title: '网页嵌入',
|
|
||||||
// desc: '嵌入到已有网页中,右下角会生成对话按键',
|
|
||||||
// value: LinkTypeEnum.iframe
|
|
||||||
// }
|
|
||||||
]}
|
]}
|
||||||
value={linkType}
|
value={linkType}
|
||||||
onChange={(e) => setLinkType(e as `${LinkTypeEnum}`)}
|
onChange={(e) => setLinkType(e as `${LinkTypeEnum}`)}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user