mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-21 11:43:56 +00:00
perf: user info framwork
This commit is contained in:
19
.github/workflows/image.yml
vendored
19
.github/workflows/image.yml
vendored
@@ -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 }
|
||||
|
@@ -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:
|
||||
|
@@ -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 |
@@ -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,
|
||||
|
@@ -42,12 +42,6 @@ const Navbar = () => {
|
||||
link: '/model/share',
|
||||
activeLink: ['/model/share']
|
||||
},
|
||||
{
|
||||
label: '邀请',
|
||||
icon: 'promotion',
|
||||
link: '/promotion',
|
||||
activeLink: ['/promotion']
|
||||
},
|
||||
{
|
||||
label: '开发',
|
||||
icon: 'develop',
|
||||
|
@@ -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>
|
||||
|
@@ -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)
|
||||
}),
|
||||
|
@@ -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
|
||||
]
|
||||
|
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
@@ -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>
|
||||
);
|
||||
};
|
||||
|
||||
|
54
src/pages/number/components/PromotionTable.tsx
Normal file
54
src/pages/number/components/PromotionTable.tsx
Normal 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;
|
@@ -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>
|
||||
);
|
||||
};
|
||||
|
@@ -61,6 +61,7 @@ const OpenApi = () => {
|
||||
的形式接入到自己的应用中,例如:飞书、企业微信、客服助手。请注意保管你的 Api
|
||||
Key,不要泄露!
|
||||
</Box>
|
||||
<Box>使用 Fast Api 功能仅能使用平台余额。</Box>
|
||||
<Box
|
||||
my={1}
|
||||
as="a"
|
||||
|
@@ -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;
|
@@ -15,11 +15,6 @@ const list = [
|
||||
label: 'AI应用市场',
|
||||
link: '/model/share'
|
||||
},
|
||||
{
|
||||
icon: 'promotion',
|
||||
label: '邀请好友',
|
||||
link: '/promotion'
|
||||
},
|
||||
{
|
||||
icon: 'develop',
|
||||
label: '开发',
|
||||
|
@@ -108,7 +108,6 @@ class Pg {
|
||||
}
|
||||
LIMIT ${props.limit || 10} OFFSET ${props.offset || 0}
|
||||
`;
|
||||
|
||||
const pg = await connectPg();
|
||||
return pg.query<T>(sql);
|
||||
}
|
||||
|
Reference in New Issue
Block a user