mirror of
https://github.com/labring/FastGPT.git
synced 2025-08-03 13:38:00 +00:00
new framwork
This commit is contained in:
72
client/src/pages/number/components/BillTable.tsx
Normal file
72
client/src/pages/number/components/BillTable.tsx
Normal file
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Flex, Box } from '@chakra-ui/react';
|
||||
import { BillTypeMap } from '@/constants/user';
|
||||
import { getUserBills } from '@/api/user';
|
||||
import type { UserBillType } from '@/types/user';
|
||||
import { usePagination } from '@/hooks/usePagination';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import dayjs from 'dayjs';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const BillTable = () => {
|
||||
const { Loading } = useLoading();
|
||||
|
||||
const {
|
||||
data: bills,
|
||||
isLoading,
|
||||
Pagination,
|
||||
pageSize,
|
||||
total
|
||||
} = usePagination<UserBillType>({
|
||||
api: getUserBills
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContainer position={'relative'} minH={'200px'}>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>时间</Th>
|
||||
<Th>类型</Th>
|
||||
<Th>底层模型</Th>
|
||||
<Th>内容长度</Th>
|
||||
<Th>Tokens 长度</Th>
|
||||
<Th>金额</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody fontSize={'sm'}>
|
||||
{bills.map((item) => (
|
||||
<Tr key={item.id}>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||
<Td>{BillTypeMap[item.type] || '-'}</Td>
|
||||
<Td>{item.modelName}</Td>
|
||||
<Td>{item.textLen}</Td>
|
||||
<Td>{item.tokenLen}</Td>
|
||||
<Td>{item.price}元</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
|
||||
<Loading loading={isLoading} fixed={false} />
|
||||
</TableContainer>
|
||||
|
||||
{!isLoading && bills.length === 0 && (
|
||||
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'200px'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
无使用记录~
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{total > pageSize && (
|
||||
<Flex w={'100%'} mt={4} justifyContent={'flex-end'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BillTable;
|
91
client/src/pages/number/components/InformTable.tsx
Normal file
91
client/src/pages/number/components/InformTable.tsx
Normal file
@@ -0,0 +1,91 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
Accordion,
|
||||
AccordionItem,
|
||||
AccordionButton,
|
||||
AccordionPanel,
|
||||
AccordionIcon
|
||||
} from '@chakra-ui/react';
|
||||
import { getInforms, readInform } from '@/api/user';
|
||||
import { usePagination } from '@/hooks/usePagination';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import type { informSchema } from '@/types/mongoSchema';
|
||||
import { formatTimeToChatTime } from '@/utils/tools';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const BillTable = () => {
|
||||
const { Loading } = useLoading();
|
||||
|
||||
const {
|
||||
data: informs,
|
||||
isLoading,
|
||||
total,
|
||||
pageSize,
|
||||
Pagination,
|
||||
getData,
|
||||
pageNum
|
||||
} = usePagination<informSchema>({
|
||||
api: getInforms
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion defaultIndex={[0, 1, 2]} allowMultiple>
|
||||
{informs.map((item) => (
|
||||
<AccordionItem
|
||||
key={item._id}
|
||||
onClick={async () => {
|
||||
if (!item.read) {
|
||||
await readInform(item._id);
|
||||
getData(pageNum);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AccordionButton>
|
||||
<Flex alignItems={'center'} flex="1" textAlign="left">
|
||||
<Box fontWeight={'bold'} position={'relative'}>
|
||||
{!item.read && (
|
||||
<Box
|
||||
w={'5px'}
|
||||
h={'5px'}
|
||||
borderRadius={'10px'}
|
||||
bg={'myRead.600'}
|
||||
position={'absolute'}
|
||||
top={1}
|
||||
left={'-5px'}
|
||||
></Box>
|
||||
)}
|
||||
{item.title}
|
||||
</Box>
|
||||
<Box ml={2} color={'myGray.500'}>
|
||||
{formatTimeToChatTime(item.time)}
|
||||
</Box>
|
||||
</Flex>
|
||||
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel pb={4}>{item.content}</AccordionPanel>
|
||||
</AccordionItem>
|
||||
))}
|
||||
</Accordion>
|
||||
{!isLoading && informs.length === 0 && (
|
||||
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'200px'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
暂无通知~
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{total > pageSize && (
|
||||
<Flex w={'100%'} mt={4} justifyContent={'flex-end'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
<Loading loading={isLoading && informs.length === 0} fixed={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default BillTable;
|
153
client/src/pages/number/components/PayModal.tsx
Normal file
153
client/src/pages/number/components/PayModal.tsx
Normal file
@@ -0,0 +1,153 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import {
|
||||
Modal,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalFooter,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
Button,
|
||||
Input,
|
||||
Box,
|
||||
Grid
|
||||
} from '@chakra-ui/react';
|
||||
import { getPayCode, checkPayResult } from '@/api/user';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useRouter } from 'next/router';
|
||||
import { getErrText } from '@/utils/tools';
|
||||
import Markdown from '@/components/Markdown';
|
||||
|
||||
const PayModal = ({ onClose }: { onClose: () => void }) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const [inputVal, setInputVal] = useState<number | ''>('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [payId, setPayId] = useState('');
|
||||
|
||||
const handleClickPay = useCallback(async () => {
|
||||
if (!inputVal || inputVal <= 0 || isNaN(+inputVal)) return;
|
||||
setLoading(true);
|
||||
try {
|
||||
// 获取支付二维码
|
||||
const res = await getPayCode(inputVal);
|
||||
new QRCode(document.getElementById('payQRCode'), {
|
||||
text: res.codeUrl,
|
||||
width: 128,
|
||||
height: 128,
|
||||
colorDark: '#000000',
|
||||
colorLight: '#ffffff',
|
||||
correctLevel: QRCode.CorrectLevel.H
|
||||
});
|
||||
setPayId(res.payId);
|
||||
} catch (err) {
|
||||
toast({
|
||||
title: getErrText(err),
|
||||
status: 'error'
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
}, [inputVal, toast]);
|
||||
|
||||
useQuery(
|
||||
[payId],
|
||||
() => {
|
||||
if (!payId) return null;
|
||||
return checkPayResult(payId);
|
||||
},
|
||||
{
|
||||
enabled: !!payId,
|
||||
refetchInterval: 2000,
|
||||
onSuccess(res) {
|
||||
if (!res) return;
|
||||
toast({
|
||||
title: '充值成功',
|
||||
status: 'success'
|
||||
});
|
||||
router.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
isOpen={true}
|
||||
onClose={() => {
|
||||
if (payId) return;
|
||||
onClose();
|
||||
}}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent minW={'auto'}>
|
||||
<ModalHeader>充值</ModalHeader>
|
||||
{!payId && <ModalCloseButton />}
|
||||
|
||||
<ModalBody py={0}>
|
||||
{!payId && (
|
||||
<>
|
||||
<Grid gridTemplateColumns={'repeat(4,1fr)'} gridGap={5} mb={4}>
|
||||
{[10, 20, 50, 100].map((item) => (
|
||||
<Button
|
||||
key={item}
|
||||
variant={item === inputVal ? 'solid' : 'outline'}
|
||||
onClick={() => setInputVal(item)}
|
||||
>
|
||||
{item}元
|
||||
</Button>
|
||||
))}
|
||||
</Grid>
|
||||
<Box mb={4}>
|
||||
<Input
|
||||
value={inputVal}
|
||||
type={'number'}
|
||||
step={1}
|
||||
placeholder={'其他金额,请取整数'}
|
||||
onChange={(e) => {
|
||||
setInputVal(Math.floor(+e.target.value));
|
||||
}}
|
||||
></Input>
|
||||
</Box>
|
||||
<Markdown
|
||||
source={`
|
||||
| 计费项 | 价格: 元/ 1K tokens(包含上下文)|
|
||||
| --- | --- |
|
||||
| 知识库 - 索引 | 0.001 |
|
||||
| chatgpt - 对话 | 0.025 |
|
||||
| gpt4 - 对话 | 0.5 |
|
||||
| 文件拆分 | 0.025 |`}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{/* 付费二维码 */}
|
||||
<Box textAlign={'center'}>
|
||||
{payId && <Box mb={3}>请微信扫码支付: {inputVal}元,请勿关闭页面</Box>}
|
||||
<Box id={'payQRCode'} display={'inline-block'}></Box>
|
||||
</Box>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
{!payId && (
|
||||
<>
|
||||
<Button variant={'outline'} onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button
|
||||
ml={3}
|
||||
isLoading={loading}
|
||||
isDisabled={!inputVal || inputVal === 0}
|
||||
onClick={handleClickPay}
|
||||
>
|
||||
获取充值二维码
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PayModal;
|
107
client/src/pages/number/components/PayRecordTable.tsx
Normal file
107
client/src/pages/number/components/PayRecordTable.tsx
Normal file
@@ -0,0 +1,107 @@
|
||||
import React, { useState, useCallback } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
Thead,
|
||||
Tbody,
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
TableContainer,
|
||||
Flex,
|
||||
Box
|
||||
} from '@chakra-ui/react';
|
||||
import { getPayOrders, checkPayResult } from '@/api/user';
|
||||
import { PaySchema } from '@/types/mongoSchema';
|
||||
import dayjs from 'dayjs';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const PayRecordTable = () => {
|
||||
const { Loading, setIsLoading } = useLoading();
|
||||
const [payOrders, setPayOrders] = useState<PaySchema[]>([]);
|
||||
const { toast } = useToast();
|
||||
|
||||
const handleRefreshPayOrder = useCallback(
|
||||
async (payId: string) => {
|
||||
setIsLoading(true);
|
||||
|
||||
try {
|
||||
const data = await checkPayResult(payId);
|
||||
toast({
|
||||
title: data,
|
||||
status: 'info'
|
||||
});
|
||||
const res = await getPayOrders();
|
||||
setPayOrders(res);
|
||||
} catch (error: any) {
|
||||
toast({
|
||||
title: error?.message,
|
||||
status: 'warning'
|
||||
});
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
setIsLoading(false);
|
||||
},
|
||||
[setIsLoading, toast]
|
||||
);
|
||||
|
||||
const { isInitialLoading } = useQuery(['initPayOrder'], getPayOrders, {
|
||||
onSuccess(res) {
|
||||
setPayOrders(res);
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>订单号</Th>
|
||||
<Th>时间</Th>
|
||||
<Th>金额</Th>
|
||||
<Th>状态</Th>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody fontSize={'sm'}>
|
||||
{payOrders.map((item) => (
|
||||
<Tr key={item._id}>
|
||||
<Td>{item.orderId}</Td>
|
||||
<Td>
|
||||
{item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
|
||||
</Td>
|
||||
<Td>{formatPrice(item.price)}元</Td>
|
||||
<Td>{item.status}</Td>
|
||||
<Td>
|
||||
{item.status === 'NOTPAY' && (
|
||||
<Button onClick={() => handleRefreshPayOrder(item._id)} size={'sm'}>
|
||||
更新
|
||||
</Button>
|
||||
)}
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{!isInitialLoading && payOrders.length === 0 && (
|
||||
<Flex h={'100%'} flexDirection={'column'} alignItems={'center'} pt={'200px'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
无支付记录~
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
<Loading loading={isInitialLoading} fixed={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PayRecordTable;
|
68
client/src/pages/number/components/PromotionTable.tsx
Normal file
68
client/src/pages/number/components/PromotionTable.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import React from 'react';
|
||||
import { Flex, Table, Thead, Tbody, Tr, Th, Td, TableContainer, Box } from '@chakra-ui/react';
|
||||
import { useLoading } from '@/hooks/useLoading';
|
||||
import dayjs from 'dayjs';
|
||||
import { getPromotionRecords } from '@/api/user';
|
||||
import { usePagination } from '@/hooks/usePagination';
|
||||
import { PromotionRecordType } from '@/api/response/user';
|
||||
import { PromotionTypeMap } from '@/constants/user';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const OpenApi = () => {
|
||||
const { Loading } = useLoading();
|
||||
|
||||
const {
|
||||
data: promotionRecords,
|
||||
isLoading,
|
||||
total,
|
||||
pageSize,
|
||||
Pagination
|
||||
} = usePagination<PromotionRecordType>({
|
||||
api: getPromotionRecords
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableContainer position={'relative'} overflow={'hidden'} minH={'200px'}>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>时间</Th>
|
||||
<Th>类型</Th>
|
||||
<Th>金额</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody fontSize={'sm'}>
|
||||
{promotionRecords.map((item) => (
|
||||
<Tr key={item._id}>
|
||||
<Td>
|
||||
{item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
|
||||
</Td>
|
||||
<Td>{PromotionTypeMap[item.type]}</Td>
|
||||
<Td>{item.amount}</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
|
||||
<Loading loading={isLoading} fixed={false} />
|
||||
</TableContainer>
|
||||
|
||||
{!isLoading && promotionRecords.length === 0 && (
|
||||
<Flex flexDirection={'column'} alignItems={'center'}>
|
||||
<MyIcon name="empty" w={'48px'} h={'48px'} color={'transparent'} />
|
||||
<Box mt={2} color={'myGray.500'}>
|
||||
无佣金记录~
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
{total > pageSize && (
|
||||
<Flex mt={4} justifyContent={'flex-end'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default OpenApi;
|
295
client/src/pages/number/index.tsx
Normal file
295
client/src/pages/number/index.tsx
Normal file
@@ -0,0 +1,295 @@
|
||||
import React, { useCallback, useRef, useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
Box,
|
||||
Flex,
|
||||
Button,
|
||||
Input,
|
||||
Grid,
|
||||
useDisclosure,
|
||||
Tabs,
|
||||
TabList,
|
||||
TabPanels,
|
||||
Tab,
|
||||
TabPanel
|
||||
} from '@chakra-ui/react';
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { UserUpdateParams } from '@/types/user';
|
||||
import { putUserInfo, getPromotionInitData } from '@/api/user';
|
||||
import { useToast } from '@/hooks/useToast';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { UserType } from '@/types/user';
|
||||
import { clearCookie } from '@/utils/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 { useCopyData } from '@/utils/tools';
|
||||
import Loading from '@/components/Loading';
|
||||
import Avatar from '@/components/Avatar';
|
||||
import MyIcon from '@/components/Icon';
|
||||
|
||||
const PayRecordTable = dynamic(() => import('./components/PayRecordTable'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const BilTable = dynamic(() => import('./components/BillTable'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const PromotionTable = dynamic(() => import('./components/PromotionTable'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const InformTable = dynamic(() => import('./components/InformTable'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const PayModal = dynamic(() => import('./components/PayModal'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
const WxConcat = dynamic(() => import('@/components/WxConcat'), {
|
||||
loading: () => <Loading fixed={false} />,
|
||||
ssr: false
|
||||
});
|
||||
|
||||
enum TableEnum {
|
||||
'bill' = 'bill',
|
||||
'pay' = 'pay',
|
||||
'promotion' = 'promotion',
|
||||
'inform' = 'inform'
|
||||
}
|
||||
|
||||
const NumberSetting = ({ tableType }: { tableType: `${TableEnum}` }) => {
|
||||
const tableList = useRef([
|
||||
{ label: '账单', value: TableEnum.bill, Component: BilTable },
|
||||
{ label: '充值', value: TableEnum.pay, Component: PayRecordTable },
|
||||
{ label: '佣金', value: TableEnum.promotion, Component: PromotionTable },
|
||||
{ label: '通知', value: TableEnum.inform, Component: InformTable }
|
||||
]);
|
||||
const router = useRouter();
|
||||
const { copyData } = useCopyData();
|
||||
const { userInfo, updateUserInfo, initUserInfo, setUserInfo } = useUserStore();
|
||||
const { setLoading } = useGlobalStore();
|
||||
const { register, handleSubmit, reset } = useForm<UserUpdateParams>({
|
||||
defaultValues: userInfo as UserType
|
||||
});
|
||||
const { toast } = useToast();
|
||||
const {
|
||||
isOpen: isOpenPayModal,
|
||||
onClose: onClosePayModal,
|
||||
onOpen: onOpenPayModal
|
||||
} = useDisclosure();
|
||||
const {
|
||||
isOpen: isOpenWxConcat,
|
||||
onClose: onCloseWxConcat,
|
||||
onOpen: onOpenWxConcat
|
||||
} = useDisclosure();
|
||||
|
||||
const { File, onOpen: onOpenSelectFile } = useSelectFile({
|
||||
fileType: '.jpg,.png',
|
||||
multiple: false
|
||||
});
|
||||
|
||||
const onclickSave = useCallback(
|
||||
async (data: UserUpdateParams) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
await putUserInfo(data);
|
||||
updateUserInfo(data);
|
||||
reset(data);
|
||||
toast({
|
||||
title: '更新成功',
|
||||
status: 'success'
|
||||
});
|
||||
} catch (error) {}
|
||||
setLoading(false);
|
||||
},
|
||||
[reset, setLoading, toast, updateUserInfo]
|
||||
);
|
||||
|
||||
const onSelectFile = useCallback(
|
||||
async (e: File[]) => {
|
||||
const file = e[0];
|
||||
if (!file) return;
|
||||
try {
|
||||
const base64 = await compressImg({
|
||||
file,
|
||||
maxW: 100,
|
||||
maxH: 100
|
||||
});
|
||||
onclickSave({
|
||||
...userInfo,
|
||||
avatar: base64
|
||||
});
|
||||
} catch (err: any) {
|
||||
toast({
|
||||
title: typeof err === 'string' ? err : '头像选择异常',
|
||||
status: 'warning'
|
||||
});
|
||||
}
|
||||
},
|
||||
[onclickSave, toast, userInfo]
|
||||
);
|
||||
|
||||
const onclickLogOut = useCallback(() => {
|
||||
clearCookie();
|
||||
setUserInfo(null);
|
||||
router.replace('/login');
|
||||
}, [router, setUserInfo]);
|
||||
|
||||
useQuery(['init'], initUserInfo, {
|
||||
onSuccess(res) {
|
||||
reset(res);
|
||||
}
|
||||
});
|
||||
const { data: { invitedAmount = 0, historyAmount = 0, residueAmount = 0 } = {} } = useQuery(
|
||||
['getPromotionInitData'],
|
||||
getPromotionInitData
|
||||
);
|
||||
|
||||
return (
|
||||
<Box py={[5, 10]} px={'5vw'}>
|
||||
<Grid gridTemplateColumns={['1fr', '3fr 300px']} gridGap={4}>
|
||||
<Card px={6} py={4}>
|
||||
<Flex justifyContent={'space-between'}>
|
||||
<Box fontSize={'xl'} fontWeight={'bold'}>
|
||||
账号信息
|
||||
</Box>
|
||||
<Button variant={'outline'} size={'xs'} onClick={onclickLogOut}>
|
||||
退出登录
|
||||
</Button>
|
||||
</Flex>
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box flex={'0 0 50px'}>头像:</Box>
|
||||
<Avatar
|
||||
src={userInfo?.avatar}
|
||||
w={['28px', '36px']}
|
||||
h={['28px', '36px']}
|
||||
cursor={'pointer'}
|
||||
title={'点击切换头像'}
|
||||
onClick={onOpenSelectFile}
|
||||
/>
|
||||
</Flex>
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box flex={'0 0 50px'}>账号:</Box>
|
||||
<Box>{userInfo?.username}</Box>
|
||||
</Flex>
|
||||
<Box mt={6}>
|
||||
<Flex alignItems={'center'}>
|
||||
<Box flex={'0 0 50px'}>余额:</Box>
|
||||
<Box>
|
||||
<strong>{userInfo?.balance}</strong> 元
|
||||
</Box>
|
||||
<Button size={['xs', 'sm']} w={['70px', '80px']} ml={5} onClick={onOpenPayModal}>
|
||||
充值
|
||||
</Button>
|
||||
</Flex>
|
||||
<Box fontSize={'xs'} color={'blackAlpha.500'}>
|
||||
如果填写了自己的 openai 账号,网页上 openai 模型对话不会计费。
|
||||
</Box>
|
||||
</Box>
|
||||
<Flex mt={6} alignItems={'center'}>
|
||||
<Box flex={'0 0 85px'}>openaiKey:</Box>
|
||||
<Input
|
||||
{...register(`openaiKey`)}
|
||||
maxW={'300px'}
|
||||
placeholder={'openai账号。回车或失去焦点保存'}
|
||||
size={'sm'}
|
||||
onBlur={handleSubmit(onclickSave)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.keyCode === 13) {
|
||||
handleSubmit(onclickSave)();
|
||||
}
|
||||
}}
|
||||
></Input>
|
||||
</Flex>
|
||||
</Card>
|
||||
<Card px={6} py={4}>
|
||||
<Box fontSize={'xl'} fontWeight={'bold'}>
|
||||
我的邀请
|
||||
</Box>
|
||||
{[
|
||||
{ label: '佣金比例', value: `${userInfo?.promotion.rate || 15}%` },
|
||||
{ label: '已注册用户数', value: `${invitedAmount}人` },
|
||||
{ label: '累计佣金', value: `¥${historyAmount}` }
|
||||
].map((item) => (
|
||||
<Flex key={item.label} alignItems={'center'} mt={4} justifyContent={'space-between'}>
|
||||
<Box w={'120px'}>{item.label}</Box>
|
||||
<Box fontWeight={'bold'}>{item.value}</Box>
|
||||
</Flex>
|
||||
))}
|
||||
<Button
|
||||
mt={4}
|
||||
variant={'outline'}
|
||||
w={'100%'}
|
||||
onClick={() =>
|
||||
copyData(`${location.origin}/?inviterId=${userInfo?._id}`, '已复制邀请链接')
|
||||
}
|
||||
>
|
||||
复制邀请链接
|
||||
</Button>
|
||||
<Button
|
||||
mt={4}
|
||||
leftIcon={<MyIcon name="withdraw" w={'22px'} />}
|
||||
px={4}
|
||||
title={residueAmount < 50 ? '最低提现额度为50元' : ''}
|
||||
isDisabled={residueAmount < 50}
|
||||
variant={'outline'}
|
||||
colorScheme={'myBlue'}
|
||||
onClick={onOpenWxConcat}
|
||||
>
|
||||
{residueAmount < 50 ? '50元起提' : '提现'}
|
||||
</Button>
|
||||
</Card>
|
||||
</Grid>
|
||||
|
||||
<Card mt={4} px={[3, 6]} py={4}>
|
||||
<Tabs
|
||||
variant="unstyled"
|
||||
isLazy
|
||||
defaultIndex={tableList.current.findIndex((item) => item.value === tableType)}
|
||||
onChange={(i) => router.replace(`/number?type=${tableList.current[i].value}`)}
|
||||
>
|
||||
<TabList whiteSpace={'nowrap'}>
|
||||
{tableList.current.map((item) => (
|
||||
<Tab
|
||||
key={item.value}
|
||||
py={'2px'}
|
||||
px={4}
|
||||
borderRadius={'sm'}
|
||||
mr={2}
|
||||
transition={'none'}
|
||||
_selected={{ color: 'white', bg: 'myBlue.600' }}
|
||||
>
|
||||
{item.label}
|
||||
</Tab>
|
||||
))}
|
||||
</TabList>
|
||||
<TabPanels>
|
||||
{tableList.current.map((Item) => (
|
||||
<TabPanel minH={'550px'} key={Item.value}>
|
||||
<Item.Component />
|
||||
</TabPanel>
|
||||
))}
|
||||
</TabPanels>
|
||||
</Tabs>
|
||||
</Card>
|
||||
|
||||
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
|
||||
{isOpenWxConcat && <WxConcat onClose={onCloseWxConcat} />}
|
||||
<File onSelect={onSelectFile} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default NumberSetting;
|
||||
|
||||
NumberSetting.getInitialProps = ({ query, req }: any) => {
|
||||
return {
|
||||
tableType: query?.type || TableEnum.bill
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user