mirror of
https://github.com/labring/FastGPT.git
synced 2025-12-24 02:01:45 +08: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:
|
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 }
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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,
|
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,
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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)
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -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
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -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>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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} />}
|
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
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 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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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应用市场',
|
label: 'AI应用市场',
|
||||||
link: '/model/share'
|
link: '/model/share'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
icon: 'promotion',
|
|
||||||
label: '邀请好友',
|
|
||||||
link: '/promotion'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
icon: 'develop',
|
icon: 'develop',
|
||||||
label: '开发',
|
label: '开发',
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user