perf: user info framwork

This commit is contained in:
archer
2023-06-06 15:44:58 +08:00
parent 1f170e1cd2
commit 941549ff04
16 changed files with 286 additions and 339 deletions

View File

@@ -62,9 +62,22 @@ jobs:
with: with:
username: ${{ secrets.DOCKER_HUB_NAME }} username: ${{ secrets.DOCKER_HUB_NAME }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }} password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Set DOCKER_REPO_TAGGED based on branch or tag
run: |
if [[ "${{ github.ref_name }}" == "main" ]]; then
echo "IMAGE_TAG=latest" >> $GITHUB_ENV
else
echo "IMAGE_TAG=${{ github.ref_name }}" >> $GITHUB_ENV
fi
- name: Pull image from GitHub Container Registry - name: Pull image from GitHub Container Registry
run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${{ github.ref_name }} env:
IMAGE_TAG: ${{ env.IMAGE_TAG }}
run: docker pull ghcr.io/${{ github.repository_owner }}/fastgpt:${ IMAGE_TAG }
- name: Tag image with Docker Hub repository name and version tag - name: Tag image with Docker Hub repository name and version tag
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${{ github.ref_name }} ${{ secrets.DOCKER_IMAGE_NAME }}:${{ github.ref_name }} env:
IMAGE_TAG: ${{ env.IMAGE_TAG }}
run: docker tag ghcr.io/${{ github.repository_owner }}/fastgpt:${ IMAGE_TAG } ${{ secrets.DOCKER_IMAGE_NAME }}:${ IMAGE_TAG }
- name: Push image to Docker Hub - name: Push image to Docker Hub
run: docker push ${{ secrets.DOCKER_IMAGE_NAME }}:${{ github.ref_name }} env:
IMAGE_TAG: ${{ env.IMAGE_TAG }}
run: docker push ${{ secrets.DOCKER_IMAGE_NAME }}:${ IMAGE_TAG }

View File

@@ -19,6 +19,7 @@ services:
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
mongodb: mongodb:
image: mongo:5.0.18 image: mongo:5.0.18
# image : registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
container_name: mongo container_name: mongo
restart: always restart: always
ports: ports:

View File

@@ -1 +0,0 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1683254589346" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1074" xmlns:xlink="http://www.w3.org/1999/xlink" width="64" height="64"><path d="M446.5084032 361.0189472m-220.5069312 0a215.4848 215.4848 0 1 0 441.01386347 0 215.4848 215.4848 0 1 0-441.01386347 0ZM620.04694507 784.5116256c0-68.92772267 33.63539307-129.9888128 85.37702826-167.69996587 0.03602027-0.02619627 0.03820373-0.08077333 0.00218347-0.1080608-26.91486293-21.45832213-56.54544427-39.6551616-88.3045024-53.96834986-0.02401387-0.0109152-0.0523936-0.00654933-0.07204053 0.009824-46.01985387 38.94457813-105.5320672 62.44187093-170.5412096 62.44187093s-124.52026453-23.4962016-170.5412096-62.44187093c-0.019648-0.01746453-0.04802667-0.0207392-0.07204054-0.009824C143.28449387 622.50178773 47.66130453 749.79343893 32.841648 900.79959573c-0.00436587 0.04038613 0.02837973 0.0753152 0.06876587 0.0753152l622.71265706 0c0.054576 0 0.0873216-0.06003413 0.05566827-0.1058784C633.19001707 867.60954667 620.04694507 827.59745493 620.04694507 784.5116256zM827.43700053 620.7826336c-90.42533867 0-163.728992 73.30365227-163.728992 163.728992s73.30365227 163.728992 163.728992 163.728992 163.728992-73.30365227 163.728992-163.728992S917.86234027 620.7826336 827.43700053 620.7826336zM911.96263893 808.52521067L851.51935253 808.52521067c-0.03820373 0-0.06876587 0.0305632-0.06876586 0.06876586l0 60.4432864c0 12.48597333-9.2812512 23.34448-21.71155627 24.51896214-14.23023253 1.34476053-26.31561493-9.93725867-26.31561493-23.90443307l0-61.05672427c0-0.03820373-0.0305632-0.06876587-0.06876587-0.06876586L742.9124544 808.52630187c-12.48597333 0-23.34448-9.2812512-24.51896213-21.71155627-1.34476053-14.23023253 9.93725867-26.31561493 23.90443306-26.31561493l61.05672427 0c0.03820373 0 0.06876587-0.0305632 0.06876587-0.06876587l0-60.4432864c0-12.48597333 9.2812512-23.34448 21.71155626-24.51896213 14.23023253-1.34476053 26.31561493 9.93725867 26.31561494 23.90443306l0 61.05672427c0 0.03820373 0.0305632 0.06876587 0.06876586 0.06876587l61.05672427 0c13.9671744 0 25.2491936 12.0853824 23.90443307 26.31561493C935.30602667 799.24396053 924.44752 808.52521067 911.96263893 808.52521067z" p-id="1075"></path></svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -8,7 +8,6 @@ const map = {
chatSend: require('./icons/chatSend.svg').default, chatSend: require('./icons/chatSend.svg').default,
develop: require('./icons/develop.svg').default, develop: require('./icons/develop.svg').default,
user: require('./icons/user.svg').default, user: require('./icons/user.svg').default,
promotion: require('./icons/promotion.svg').default,
delete: require('./icons/delete.svg').default, delete: require('./icons/delete.svg').default,
withdraw: require('./icons/withdraw.svg').default, withdraw: require('./icons/withdraw.svg').default,
stop: require('./icons/stop.svg').default, stop: require('./icons/stop.svg').default,

View File

@@ -42,12 +42,6 @@ const Navbar = () => {
link: '/model/share', link: '/model/share',
activeLink: ['/model/share'] activeLink: ['/model/share']
}, },
{
label: '邀请',
icon: 'promotion',
link: '/promotion',
activeLink: ['/promotion']
},
{ {
label: '开发', label: '开发',
icon: 'develop', icon: 'develop',

View File

@@ -9,7 +9,6 @@ import {
ModalFooter, ModalFooter,
ModalBody, ModalBody,
ModalCloseButton, ModalCloseButton,
useColorModeValue,
Image Image
} from '@chakra-ui/react'; } from '@chakra-ui/react';
@@ -18,7 +17,7 @@ const WxConcat = ({ onClose }: { onClose: () => void }) => {
<Modal isOpen={true} onClose={onClose}> <Modal isOpen={true} onClose={onClose}>
<ModalOverlay /> <ModalOverlay />
<ModalContent> <ModalContent>
<ModalHeader>wx交流群</ModalHeader> <ModalHeader>-wx</ModalHeader>
<ModalCloseButton /> <ModalCloseButton />
<ModalBody textAlign={'center'}> <ModalBody textAlign={'center'}>
<Image <Image
@@ -28,12 +27,6 @@ const WxConcat = ({ onClose }: { onClose: () => void }) => {
height={'200px'} height={'200px'}
alt="" alt=""
/> />
<Box mt={2}>
:
<Box as={'span'} userSelect={'all'}>
YNyiqi
</Box>
</Box>
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>

View File

@@ -43,6 +43,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse<
PgClient.select<KbDataItemType>('modelData', { PgClient.select<KbDataItemType>('modelData', {
fields: ['id', 'q', 'a', 'source'], fields: ['id', 'q', 'a', 'source'],
where, where,
order: [{ field: 'id', mode: 'DESC' }],
limit: pageSize, limit: pageSize,
offset: pageSize * (pageNum - 1) offset: pageSize * (pageNum - 1)
}), }),

View File

@@ -17,7 +17,7 @@ const Login = () => {
const { lastRoute = '' } = router.query as { lastRoute: string }; const { lastRoute = '' } = router.query as { lastRoute: string };
const { isPc } = useGlobalStore(); const { isPc } = useGlobalStore();
const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login); const [pageType, setPageType] = useState<`${PageTypeEnum}`>(PageTypeEnum.login);
const { setUserInfo, setLastModelId, loadMyModels } = useUserStore(); const { setUserInfo, setLastModelId, loadMyModels, loadKbList, setLastKbId } = useUserStore();
const { setLastChatId, setLastChatModelId, loadHistory } = useChatStore(); const { setLastChatId, setLastChatModelId, loadHistory } = useChatStore();
const loginSuccess = useCallback( const loginSuccess = useCallback(
@@ -26,7 +26,9 @@ const Login = () => {
setLastChatId(''); setLastChatId('');
setLastModelId(''); setLastModelId('');
setLastChatModelId(''); setLastChatModelId('');
setLastKbId('');
loadMyModels(true); loadMyModels(true);
loadKbList(true);
loadHistory({ pageNum: 1, init: true }); loadHistory({ pageNum: 1, init: true });
setUserInfo(res.user); setUserInfo(res.user);
@@ -37,10 +39,12 @@ const Login = () => {
[ [
lastRoute, lastRoute,
loadHistory, loadHistory,
loadKbList,
loadMyModels, loadMyModels,
router, router,
setLastChatId, setLastChatId,
setLastChatModelId, setLastChatModelId,
setLastKbId,
setLastModelId, setLastModelId,
setUserInfo setUserInfo
] ]

View File

@@ -1,5 +1,5 @@
import React from 'react'; import React from 'react';
import { Card, Box, Table, Thead, Tbody, Tr, Th, Td, TableContainer, Flex } from '@chakra-ui/react'; import { Table, Thead, Tbody, Tr, Th, Td, TableContainer, Flex } from '@chakra-ui/react';
import { BillTypeMap } from '@/constants/user'; import { BillTypeMap } from '@/constants/user';
import { getUserBills } from '@/api/user'; import { getUserBills } from '@/api/user';
import type { UserBillType } from '@/types/user'; import type { UserBillType } from '@/types/user';
@@ -19,11 +19,8 @@ const BillTable = () => {
}); });
return ( return (
<Card mt={6} py={4}> <>
<Box fontSize={'xl'} fontWeight={'bold'} px={6} mb={1}> <TableContainer position={'relative'} minH={'200px'}>
使
</Box>
<TableContainer position={'relative'}>
<Table> <Table>
<Thead> <Thead>
<Tr> <Tr>
@@ -51,10 +48,10 @@ const BillTable = () => {
<Loading loading={isLoading} fixed={false} /> <Loading loading={isLoading} fixed={false} />
</TableContainer> </TableContainer>
<Flex mt={4} px={4} justifyContent={'flex-end'}> <Flex w={'100%'} mt={4} justifyContent={'flex-end'}>
<Pagination /> <Pagination />
</Flex> </Flex>
</Card> </>
); );
}; };

View File

@@ -1,29 +1,14 @@
import React, { useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { import { Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } from '@chakra-ui/react';
Card,
Box,
Flex,
Button,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
TableContainer,
useDisclosure
} from '@chakra-ui/react';
import { getPayOrders, checkPayResult } from '@/api/user'; import { getPayOrders, checkPayResult } from '@/api/user';
import { PaySchema } from '@/types/mongoSchema'; import { PaySchema } from '@/types/mongoSchema';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { useQuery } from '@tanstack/react-query'; import { useQuery } from '@tanstack/react-query';
import { formatPrice } from '@/utils/user'; import { formatPrice } from '@/utils/user';
import WxConcat from '@/components/WxConcat';
import { useGlobalStore } from '@/store/global'; import { useGlobalStore } from '@/store/global';
import { useToast } from '@/hooks/useToast'; import { useToast } from '@/hooks/useToast';
const PayRecordTable = () => { const PayRecordTable = () => {
const { isOpen: isOpenWx, onOpen: onOpenWx, onClose: onCloseWx } = useDisclosure();
const [payOrders, setPayOrders] = useState<PaySchema[]>([]); const [payOrders, setPayOrders] = useState<PaySchema[]>([]);
const { setLoading } = useGlobalStore(); const { setLoading } = useGlobalStore();
const { toast } = useToast(); const { toast } = useToast();
@@ -60,52 +45,38 @@ const PayRecordTable = () => {
}); });
return ( return (
<> <TableContainer>
<Card mt={6} py={4}> <Table>
<Flex alignItems={'flex-end'} px={6} mb={1}> <Thead>
<Box fontSize={'xl'} fontWeight={'bold'}> <Tr>
<Th></Th>
</Box> <Th></Th>
<Button onClick={onOpenWx} size={'xs'} ml={4} variant={'outline'}> <Th></Th>
wx联系 <Th></Th>
</Button> <Th></Th>
</Flex> </Tr>
<TableContainer px={6}> </Thead>
<Table> <Tbody fontSize={'sm'}>
<Thead> {payOrders.map((item) => (
<Tr> <Tr key={item._id}>
<Th></Th> <Td>{item.orderId}</Td>
<Th></Th> <Td>
<Th></Th> {item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'}
<Th></Th> </Td>
<Th></Th> <Td>{formatPrice(item.price)}</Td>
</Tr> <Td>{item.status}</Td>
</Thead> <Td>
<Tbody fontSize={'sm'}> {item.status === 'NOTPAY' && (
{payOrders.map((item) => ( <Button onClick={() => handleRefreshPayOrder(item._id)} size={'sm'}>
<Tr key={item._id}>
<Td>{item.orderId}</Td> </Button>
<Td> )}
{item.createTime ? dayjs(item.createTime).format('YYYY/MM/DD HH:mm:ss') : '-'} </Td>
</Td> </Tr>
<Td>{formatPrice(item.price)}</Td> ))}
<Td>{item.status}</Td> </Tbody>
<Td> </Table>
{item.status === 'NOTPAY' && ( </TableContainer>
<Button onClick={() => handleRefreshPayOrder(item._id)} size={'sm'}>
</Button>
)}
</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Card>
{/* wx 联系 */}
{isOpenWx && <WxConcat onClose={onCloseWx} />}
</>
); );
}; };

View File

@@ -0,0 +1,54 @@
import React from 'react';
import { Flex, Table, Thead, Tbody, Tr, Th, Td, TableContainer } 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';
const OpenApi = () => {
const { Loading } = useLoading();
const {
data: promotionRecords,
isLoading,
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>
<Flex mt={4} justifyContent={'flex-end'}>
<Pagination />
</Flex>
</>
);
};
export default OpenApi;

View File

@@ -1,8 +1,21 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback, useRef, useState } from 'react';
import { Card, Box, Flex, Button, Input } from '@chakra-ui/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 { useForm } from 'react-hook-form';
import { UserUpdateParams } from '@/types/user'; import { UserUpdateParams } from '@/types/user';
import { putUserInfo } from '@/api/user'; import { putUserInfo, getPromotionInitData } from '@/api/user';
import { useToast } from '@/hooks/useToast'; 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';
@@ -13,8 +26,10 @@ 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 { useCopyData } from '@/utils/tools';
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';
const PayRecordTable = dynamic(() => import('./components/PayRecordTable'), { const PayRecordTable = dynamic(() => import('./components/PayRecordTable'), {
loading: () => <Loading fixed={false} />, loading: () => <Loading fixed={false} />,
@@ -24,20 +39,49 @@ const BilTable = dynamic(() => import('./components/BillTable'), {
loading: () => <Loading fixed={false} />, loading: () => <Loading fixed={false} />,
ssr: false ssr: false
}); });
const PromotionTable = dynamic(() => import('./components/PromotionTable'), {
loading: () => <Loading fixed={false} />,
ssr: false
});
const PayModal = dynamic(() => import('./components/PayModal'), { const PayModal = dynamic(() => import('./components/PayModal'), {
loading: () => <Loading fixed={false} />, loading: () => <Loading fixed={false} />,
ssr: false ssr: false
}); });
const WxConcat = dynamic(() => import('@/components/WxConcat'), {
loading: () => <Loading fixed={false} />,
ssr: false
});
enum TableEnum {
'bill' = 'bill',
'pay' = 'pay',
'promotion' = 'promotion'
}
const NumberSetting = () => { const NumberSetting = () => {
const tableType = useRef([
{ label: '账单详情', value: TableEnum.bill, Component: BilTable },
{ label: '充值记录', value: TableEnum.pay, Component: PayRecordTable },
{ label: '佣金记录', value: TableEnum.pay, Component: PromotionTable }
]);
const router = useRouter(); const router = useRouter();
const { copyData } = useCopyData();
const { userInfo, updateUserInfo, initUserInfo, setUserInfo } = useUserStore(); const { userInfo, updateUserInfo, initUserInfo, setUserInfo } = useUserStore();
const { setLoading } = useGlobalStore(); const { setLoading } = useGlobalStore();
const { register, handleSubmit, reset } = useForm<UserUpdateParams>({ const { register, handleSubmit, reset } = useForm<UserUpdateParams>({
defaultValues: userInfo as UserType defaultValues: userInfo as UserType
}); });
const [showPay, setShowPay] = useState(false);
const { toast } = useToast(); const { toast } = useToast();
const {
isOpen: isOpenPayModal,
onClose: onClosePayModal,
onOpen: onOpenPayModal
} = useDisclosure();
const {
isOpen: isOpenWxConcat,
onClose: onCloseWxConcat,
onOpen: onOpenWxConcat
} = useDisclosure();
const { File, onOpen: onOpenSelectFile } = useSelectFile({ const { File, onOpen: onOpenSelectFile } = useSelectFile({
fileType: '.jpg,.png', fileType: '.jpg,.png',
@@ -92,76 +136,137 @@ const NumberSetting = () => {
}, [router, setUserInfo]); }, [router, setUserInfo]);
useQuery(['init'], initUserInfo); useQuery(['init'], initUserInfo);
const { data: { invitedAmount = 0, historyAmount = 0, residueAmount = 0 } = {} } = useQuery(
['getPromotionInitData'],
getPromotionInitData
);
return ( return (
<Box py={[5, 10]} px={'5vw'}> <Box py={[5, 10]} px={'5vw'}>
{/* 核心信息 */} <Grid gridTemplateColumns={['1fr', '3fr 300px']} gridGap={4}>
<Card px={6} py={4}> <Card px={6} py={4}>
<Flex justifyContent={'space-between'}> <Flex justifyContent={'space-between'}>
<Box fontSize={'xl'} fontWeight={'bold'}> <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> </Box>
<Button <Button variant={'outline'} size={'xs'} onClick={onclickLogOut}>
size={['xs', 'sm']} 退
w={['70px', '80px']}
ml={5}
onClick={() => setShowPay(true)}
>
</Button> </Button>
</Flex> </Flex>
<Box fontSize={'xs'} color={'blackAlpha.500'}> <Flex mt={6} alignItems={'center'}>
openai openai <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> </Box>
</Box> <Flex mt={6} alignItems={'center'}>
<Flex mt={6} alignItems={'center'}> <Box flex={'0 0 85px'}>openaiKey:</Box>
<Box flex={'0 0 85px'}>openaiKey:</Box> <Input
<Input {...register(`openaiKey`)}
{...register(`openaiKey`)} maxW={'300px'}
maxW={'300px'} placeholder={'openai账号。回车或失去焦点保存'}
placeholder={'openai账号。回车或失去焦点保存'} size={'sm'}
size={'sm'} onBlur={handleSubmit(onclickSave)}
onBlur={handleSubmit(onclickSave)} onKeyDown={(e) => {
onKeyDown={(e) => { if (e.keyCode === 13) {
if (e.keyCode === 13) { handleSubmit(onclickSave)();
handleSubmit(onclickSave)(); }
} }}
}} ></Input>
></Input> </Flex>
</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}
>
</Button>
</Card>
</Grid>
<Card mt={4} px={[3, 6]} py={4}>
<Tabs variant="unstyled" isLazy>
<TabList whiteSpace={'nowrap'}>
{tableType.current.map((item) => (
<Tab
key={item.value}
py={1}
px={3}
borderRadius={'sm'}
mr={1}
transition={'none'}
_selected={{ color: 'white', bg: 'myBlue.600' }}
>
{item.label}
</Tab>
))}
</TabList>
<TabPanels>
{tableType.current.map((Item) => (
<TabPanel minH={'550px'} key={Item.value}>
<Item.Component />
</TabPanel>
))}
</TabPanels>
</Tabs>
</Card> </Card>
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
{isOpenWxConcat && <WxConcat onClose={onCloseWxConcat} />}
<File onSelect={onSelectFile} /> <File onSelect={onSelectFile} />
{/* 充值记录 */}
<PayRecordTable />
{/* 账单表 */}
<BilTable />
{showPay && <PayModal onClose={() => setShowPay(false)} />}
</Box> </Box>
); );
}; };

View File

@@ -61,6 +61,7 @@ const OpenApi = () => {
Api Api
Key Key
</Box> </Box>
<Box>使 Fast Api 使</Box>
<Box <Box
my={1} my={1}
as="a" as="a"

View File

@@ -1,179 +0,0 @@
import React, { useState } from 'react';
import Link from 'next/link';
import {
Card,
Box,
Button,
Flex,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
TableContainer,
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
useColorModeValue,
ModalFooter,
useDisclosure
} from '@chakra-ui/react';
import { useQuery } from '@tanstack/react-query';
import { useLoading } from '@/hooks/useLoading';
import dayjs from 'dayjs';
import { useCopyData } from '@/utils/tools';
import { useUserStore } from '@/store/user';
import MyIcon from '@/components/Icon';
import { getPromotionRecords } from '@/api/user';
import { usePagination } from '@/hooks/usePagination';
import { PromotionRecordType } from '@/api/response/user';
import { PromotionTypeMap } from '@/constants/user';
import { getPromotionInitData } from '@/api/user';
import Image from 'next/image';
const OpenApi = () => {
const { Loading } = useLoading();
const { userInfo, initUserInfo } = useUserStore();
const { copyData } = useCopyData();
const {
isOpen: isOpenWithdraw,
onClose: onCloseWithdraw,
onOpen: onOpenWithdraw
} = useDisclosure();
useQuery(['init'], initUserInfo);
const { data: { invitedAmount = 0, historyAmount = 0, residueAmount = 0 } = {} } = useQuery(
['getPromotionInitData'],
getPromotionInitData
);
const {
data: promotionRecords,
isLoading,
Pagination,
total
} = usePagination<PromotionRecordType>({
api: getPromotionRecords
});
return (
<Box py={[5, 10]} px={'5vw'}>
<Card px={6} py={4} position={'relative'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
<Box my={2} color={'blackAlpha.600'} fontSize={'sm'}>
FastGpt FastGpt
</Box>
<Flex my={2} alignItems={'center'}>
<Box>: </Box>
<Box mx={2} fontSize={'xl'} lineHeight={1} fontWeight={'bold'}>
{residueAmount}
</Box>
</Flex>
<Flex>
<Button
mr={4}
variant={'outline'}
onClick={() => {
copyData(`${location.origin}/?inviterId=${userInfo?._id}`, '已复制邀请链接');
}}
>
</Button>
<Button
leftIcon={<MyIcon name="withdraw" w={'22px'} />}
px={4}
title={residueAmount < 50 ? '最低提现额度为50元' : ''}
isDisabled={residueAmount < 50}
onClick={onOpenWithdraw}
>
</Button>
</Flex>
</Card>
<Card mt={4} px={6} py={4} position={'relative'}>
<Flex alignItems={'center'} mb={3} justifyContent={['space-between', 'flex-start']}>
<Box w={'120px'}></Box>
<Box fontWeight={'bold'}>{userInfo?.promotion.rate || 15}%</Box>
</Flex>
<Flex alignItems={'center'} mb={3} justifyContent={['space-between', 'flex-start']}>
<Box w={'120px'}></Box>
<Box fontWeight={'bold'}>{invitedAmount}</Box>
</Flex>
<Flex alignItems={'center'} justifyContent={['space-between', 'flex-start']}>
<Box w={'120px'}></Box>
<Box fontWeight={'bold'}> {historyAmount}</Box>
</Flex>
</Card>
<Card mt={4} px={6} py={4} position={'relative'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
({total})
</Box>
<TableContainer position={'relative'}>
<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>
<Flex mt={4} px={4} justifyContent={'flex-end'}>
<Pagination />
</Flex>
</Card>
<Modal isOpen={isOpenWithdraw} onClose={onCloseWithdraw}>
<ModalOverlay />
<ModalContent color={useColorModeValue('blackAlpha.700', 'white')}>
<ModalHeader></ModalHeader>
<ModalCloseButton />
<ModalBody textAlign={'center'}>
<Image
style={{ margin: 'auto' }}
src={'/imgs/wx300-2.jpg'}
width={200}
height={200}
alt=""
/>
<Box mt={2}>
:
<Box as={'span'} userSelect={'all'}>
YNyiqi
</Box>
</Box>
<Box></Box>
</ModalBody>
<ModalFooter>
<Button variant={'outline'} onClick={onCloseWithdraw}>
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</Box>
);
};
export default OpenApi;

View File

@@ -15,11 +15,6 @@ const list = [
label: 'AI应用市场', label: 'AI应用市场',
link: '/model/share' link: '/model/share'
}, },
{
icon: 'promotion',
label: '邀请好友',
link: '/promotion'
},
{ {
icon: 'develop', icon: 'develop',
label: '开发', label: '开发',

View File

@@ -108,7 +108,6 @@ class Pg {
} }
LIMIT ${props.limit || 10} OFFSET ${props.offset || 0} LIMIT ${props.limit || 10} OFFSET ${props.offset || 0}
`; `;
const pg = await connectPg(); const pg = await connectPg();
return pg.query<T>(sql); return pg.query<T>(sql);
} }