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:
username: ${{ secrets.DOCKER_HUB_NAME }}
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
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
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
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
mongodb:
image: mongo:5.0.18
# image : registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 # 阿里云
container_name: mongo
restart: always
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,
develop: require('./icons/develop.svg').default,
user: require('./icons/user.svg').default,
promotion: require('./icons/promotion.svg').default,
delete: require('./icons/delete.svg').default,
withdraw: require('./icons/withdraw.svg').default,
stop: require('./icons/stop.svg').default,

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ const Login = () => {
const { lastRoute = '' } = router.query as { lastRoute: string };
const { isPc } = useGlobalStore();
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 loginSuccess = useCallback(
@@ -26,7 +26,9 @@ const Login = () => {
setLastChatId('');
setLastModelId('');
setLastChatModelId('');
setLastKbId('');
loadMyModels(true);
loadKbList(true);
loadHistory({ pageNum: 1, init: true });
setUserInfo(res.user);
@@ -37,10 +39,12 @@ const Login = () => {
[
lastRoute,
loadHistory,
loadKbList,
loadMyModels,
router,
setLastChatId,
setLastChatModelId,
setLastKbId,
setLastModelId,
setUserInfo
]

View File

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

View File

@@ -1,29 +1,14 @@
import React, { useState, useCallback } from 'react';
import {
Card,
Box,
Flex,
Button,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
TableContainer,
useDisclosure
} from '@chakra-ui/react';
import { Button, Table, Thead, Tbody, Tr, Th, Td, TableContainer } 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 WxConcat from '@/components/WxConcat';
import { useGlobalStore } from '@/store/global';
import { useToast } from '@/hooks/useToast';
const PayRecordTable = () => {
const { isOpen: isOpenWx, onOpen: onOpenWx, onClose: onCloseWx } = useDisclosure();
const [payOrders, setPayOrders] = useState<PaySchema[]>([]);
const { setLoading } = useGlobalStore();
const { toast } = useToast();
@@ -60,52 +45,38 @@ const PayRecordTable = () => {
});
return (
<>
<Card mt={6} py={4}>
<Flex alignItems={'flex-end'} px={6} mb={1}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
<Button onClick={onOpenWx} size={'xs'} ml={4} variant={'outline'}>
wx联系
</Button>
</Flex>
<TableContainer px={6}>
<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>
</Card>
{/* wx 联系 */}
{isOpenWx && <WxConcat onClose={onCloseWx} />}
</>
<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>
);
};

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 { Card, Box, Flex, Button, Input } from '@chakra-ui/react';
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 } from '@/api/user';
import { putUserInfo, getPromotionInitData } from '@/api/user';
import { useToast } from '@/hooks/useToast';
import { useGlobalStore } from '@/store/global';
import { useUserStore } from '@/store/user';
@@ -13,8 +26,10 @@ 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} />,
@@ -24,20 +39,49 @@ 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 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'
}
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 { copyData } = useCopyData();
const { userInfo, updateUserInfo, initUserInfo, setUserInfo } = useUserStore();
const { setLoading } = useGlobalStore();
const { register, handleSubmit, reset } = useForm<UserUpdateParams>({
defaultValues: userInfo as UserType
});
const [showPay, setShowPay] = useState(false);
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',
@@ -92,76 +136,137 @@ const NumberSetting = () => {
}, [router, setUserInfo]);
useQuery(['init'], initUserInfo);
const { data: { invitedAmount = 0, historyAmount = 0, residueAmount = 0 } = {} } = useQuery(
['getPromotionInitData'],
getPromotionInitData
);
return (
<Box py={[5, 10]} px={'5vw'}>
{/* 核心信息 */}
<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>
<Grid gridTemplateColumns={['1fr', '3fr 300px']} gridGap={4}>
<Card px={6} py={4}>
<Flex justifyContent={'space-between'}>
<Box fontSize={'xl'} fontWeight={'bold'}>
</Box>
<Button
size={['xs', 'sm']}
w={['70px', '80px']}
ml={5}
onClick={() => setShowPay(true)}
>
<Button variant={'outline'} size={'xs'} onClick={onclickLogOut}>
退
</Button>
</Flex>
<Box fontSize={'xs'} color={'blackAlpha.500'}>
openai openai
<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>
</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>
<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}
>
</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>
{isOpenPayModal && <PayModal onClose={onClosePayModal} />}
{isOpenWxConcat && <WxConcat onClose={onCloseWxConcat} />}
<File onSelect={onSelectFile} />
{/* 充值记录 */}
<PayRecordTable />
{/* 账单表 */}
<BilTable />
{showPay && <PayModal onClose={() => setShowPay(false)} />}
</Box>
);
};

View File

@@ -61,6 +61,7 @@ const OpenApi = () => {
Api
Key
</Box>
<Box>使 Fast Api 使</Box>
<Box
my={1}
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应用市场',
link: '/model/share'
},
{
icon: 'promotion',
label: '邀请好友',
link: '/promotion'
},
{
icon: 'develop',
label: '开发',

View File

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