mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-27 08:25:07 +00:00
update password
This commit is contained in:
@@ -33,6 +33,10 @@
|
||||
},
|
||||
"user": {
|
||||
"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": {
|
||||
"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;
|
||||
}) => POST('/user/sendAuthCode', data);
|
||||
|
||||
export const getTokenLogin = () => GET<UserType>('/user/tokenLogin');
|
||||
export const getTokenLogin = () => GET<UserType>('/user/account/tokenLogin');
|
||||
|
||||
export const postRegister = ({
|
||||
username,
|
||||
@@ -25,7 +25,7 @@ export const postRegister = ({
|
||||
password: string;
|
||||
inviterId: string;
|
||||
}) =>
|
||||
POST<ResLogin>('/user/register', {
|
||||
POST<ResLogin>('/user/account/register', {
|
||||
username,
|
||||
code,
|
||||
inviterId,
|
||||
@@ -41,21 +41,27 @@ export const postFindPassword = ({
|
||||
code: string;
|
||||
password: string;
|
||||
}) =>
|
||||
POST<ResLogin>('/user/updatePasswordByCode', {
|
||||
POST<ResLogin>('/user/account/updatePasswordByCode', {
|
||||
username,
|
||||
code,
|
||||
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 }) =>
|
||||
POST<ResLogin>('/user/loginByPassword', {
|
||||
POST<ResLogin>('/user/account/loginByPassword', {
|
||||
username,
|
||||
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) =>
|
||||
POST<PagingData<UserBillType>>(`/user/getBill`, data);
|
||||
|
@@ -2,14 +2,16 @@ import { useToast } from '@/hooks/useToast';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import type { UseMutationOptions } from '@tanstack/react-query';
|
||||
import { getErrText } from '@/utils/tools';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface Props extends UseMutationOptions<any, any, any, any> {
|
||||
successToast?: string;
|
||||
errorToast?: string;
|
||||
successToast?: string | null;
|
||||
errorToast?: string | null;
|
||||
}
|
||||
|
||||
export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...props }: Props) => {
|
||||
const { toast } = useToast();
|
||||
const { t } = useTranslation();
|
||||
const mutation = useMutation<unknown, unknown, any, unknown>({
|
||||
...props,
|
||||
onSuccess(res, variables: void, context: unknown) {
|
||||
@@ -24,7 +26,7 @@ export const useRequest = ({ successToast, errorToast, onSuccess, onError, ...pr
|
||||
onError?.(err, variables, context);
|
||||
errorToast &&
|
||||
toast({
|
||||
title: getErrText(err, errorToast),
|
||||
title: t(getErrText(err, errorToast)),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
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 { UserUpdateParams } from '@/types/user';
|
||||
import { putUserInfo } from '@/api/user';
|
||||
@@ -7,35 +7,48 @@ import { useToast } from '@/hooks/useToast';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { UserType } from '@/types/user';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import dynamic from 'next/dynamic';
|
||||
import { useSelectFile } from '@/hooks/useSelectFile';
|
||||
import { compressImg } from '@/utils/file';
|
||||
import { getErrText } from '@/utils/tools';
|
||||
import { feConfigs } from '@/store/static';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import Loading from '@/components/Loading';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
import MyTooltip from '@/components/MyTooltip';
|
||||
|
||||
const PayModal = dynamic(() => import('./PayModal'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const UpdatePswModal = dynamic(() => import('./UpdatePswModal'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
|
||||
const UserInfo = () => {
|
||||
const router = useRouter();
|
||||
const theme = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const { userInfo, updateUserInfo, initUserInfo } = useUserStore();
|
||||
const { setLoading } = useGlobalStore();
|
||||
const { reset } = useForm<UserUpdateParams>({
|
||||
const { reset, register } = useForm<UserUpdateParams>({
|
||||
defaultValues: userInfo as UserType
|
||||
});
|
||||
|
||||
const { toast } = useToast();
|
||||
const {
|
||||
isOpen: isOpenPayModal,
|
||||
onClose: onClosePayModal,
|
||||
onOpen: onOpenPayModal
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenUpdatePsw,
|
||||
onClose: onCloseUpdatePsw,
|
||||
onOpen: onOpenUpdatePsw
|
||||
} = useDisclosure();
|
||||
const { File, onOpen: onOpenSelectFile } = useSelectFile({
|
||||
fileType: '.jpg,.png',
|
||||
multiple: false
|
||||
@@ -98,41 +111,68 @@ const UserInfo = () => {
|
||||
}
|
||||
});
|
||||
return (
|
||||
<Flex flexDirection={'column'} alignItems={'center'} py={[0, 8]} fontSize={['lg', 'xl']}>
|
||||
<Flex mt={6} alignItems={'center'} w={'260px'}>
|
||||
<Box flex={'0 0 50px'}>头像:</Box>
|
||||
<Box flex={1} pl={10}>
|
||||
<Avatar
|
||||
src={userInfo?.avatar}
|
||||
w={['34px', '44px']}
|
||||
h={['34px', '44px']}
|
||||
cursor={'pointer'}
|
||||
title={'点击切换头像'}
|
||||
onClick={onOpenSelectFile}
|
||||
/>
|
||||
</Box>
|
||||
<Box display={['block', 'flex']} py={[2, 10]} justifyContent={'center'} fontSize={['lg', 'xl']}>
|
||||
<Flex
|
||||
flexDirection={'column'}
|
||||
alignItems={'center'}
|
||||
cursor={'pointer'}
|
||||
onClick={onOpenSelectFile}
|
||||
>
|
||||
<MyTooltip label={'更换头像'}>
|
||||
<Box
|
||||
w={['44px', '54px']}
|
||||
h={['44px', '54px']}
|
||||
borderRadius={'50%'}
|
||||
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 mt={6} alignItems={'center'} w={'260px'}>
|
||||
<Box flex={'0 0 50px'}>账号:</Box>
|
||||
<Box>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
{feConfigs?.show_userDetail && (
|
||||
<Box mt={6} w={'260px'} whiteSpace={'nowrap'}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'0 0 50px'}>余额:</Box>
|
||||
<Box>
|
||||
<strong>{userInfo?.balance.toFixed(3)}</strong> 元
|
||||
</Box>
|
||||
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
|
||||
充值
|
||||
</Button>
|
||||
</Flex>
|
||||
</Box>
|
||||
)}
|
||||
<Box
|
||||
display={['flex', 'block']}
|
||||
flexDirection={'column'}
|
||||
alignItems={'center'}
|
||||
ml={[0, 10]}
|
||||
mt={[6, 0]}
|
||||
>
|
||||
<Flex alignItems={'center'} w={['85%', '300px']}>
|
||||
<Box flex={'0 0 50px'}>账号:</Box>
|
||||
<Box flex={1}>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
<Flex mt={6} alignItems={'center'} w={['85%', '300px']}>
|
||||
<Box flex={'0 0 50px'}>密码:</Box>
|
||||
<Box flex={1}>*****</Box>
|
||||
<Button size={['sm', 'md']} variant={'base'} ml={5} onClick={onOpenUpdatePsw}>
|
||||
变更
|
||||
</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} />}
|
||||
{isOpenUpdatePsw && <UpdatePswModal onClose={onCloseUpdatePsw} />}
|
||||
<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 (
|
||||
<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'}>
|
||||
<Box fontWeight={'bold'}>
|
||||
免登录窗口
|
||||
@@ -222,7 +222,7 @@ const OutLink = ({ appId }: { appId: string }) => {
|
||||
</Box>
|
||||
<Box pb={[5, 7]} px={[4, 8]} borderBottom={theme.borders.base}>
|
||||
<MyRadio
|
||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(2, 350px)']}
|
||||
gridTemplateColumns={['repeat(1,1fr)', 'repeat(auto-fill, minmax(0, 360px))']}
|
||||
iconSize={'20px'}
|
||||
list={[
|
||||
{
|
||||
@@ -230,13 +230,13 @@ const OutLink = ({ appId }: { appId: string }) => {
|
||||
title: '免登录窗口',
|
||||
desc: '分享链接给其他用户,无需登录即可直接进行使用',
|
||||
value: LinkTypeEnum.share
|
||||
},
|
||||
{
|
||||
icon: 'outlink_iframe',
|
||||
title: '网页嵌入',
|
||||
desc: '嵌入到已有网页中,右下角会生成对话按键',
|
||||
value: LinkTypeEnum.iframe
|
||||
}
|
||||
// {
|
||||
// icon: 'outlink_iframe',
|
||||
// title: '网页嵌入',
|
||||
// desc: '嵌入到已有网页中,右下角会生成对话按键',
|
||||
// value: LinkTypeEnum.iframe
|
||||
// }
|
||||
]}
|
||||
value={linkType}
|
||||
onChange={(e) => setLinkType(e as `${LinkTypeEnum}`)}
|
||||
|
Reference in New Issue
Block a user