mirror of
https://github.com/labring/FastGPT.git
synced 2025-07-23 13:03:50 +00:00
feat: 滚动加载组件
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
"hyperdown": "^2.4.29",
|
||||
"immer": "^9.0.19",
|
||||
"jsonwebtoken": "^9.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"mammoth": "^1.5.1",
|
||||
"mongoose": "^6.10.0",
|
||||
"nanoid": "^4.0.1",
|
||||
@@ -51,6 +52,7 @@
|
||||
"@svgr/webpack": "^6.5.1",
|
||||
"@types/formidable": "^2.0.5",
|
||||
"@types/jsonwebtoken": "^9.0.1",
|
||||
"@types/lodash": "^4.14.191",
|
||||
"@types/node": "18.14.0",
|
||||
"@types/nodemailer": "^6.4.7",
|
||||
"@types/react": "18.0.28",
|
||||
|
5
pnpm-lock.yaml
generated
5
pnpm-lock.yaml
generated
@@ -10,6 +10,7 @@ specifiers:
|
||||
'@tanstack/react-query': ^4.24.10
|
||||
'@types/formidable': ^2.0.5
|
||||
'@types/jsonwebtoken': ^9.0.1
|
||||
'@types/lodash': ^4.14.191
|
||||
'@types/node': 18.14.0
|
||||
'@types/nodemailer': ^6.4.7
|
||||
'@types/nprogress': ^0.2.0
|
||||
@@ -31,6 +32,7 @@ specifiers:
|
||||
immer: ^9.0.19
|
||||
jsonwebtoken: ^9.0.0
|
||||
lint-staged: ^13.1.2
|
||||
lodash: ^4.17.21
|
||||
mammoth: ^1.5.1
|
||||
mongoose: ^6.10.0
|
||||
nanoid: ^4.0.1
|
||||
@@ -70,6 +72,7 @@ dependencies:
|
||||
hyperdown: registry.npmmirror.com/hyperdown/2.4.29
|
||||
immer: registry.npmmirror.com/immer/9.0.19
|
||||
jsonwebtoken: registry.npmmirror.com/jsonwebtoken/9.0.0
|
||||
lodash: registry.npmmirror.com/lodash/4.17.21
|
||||
mammoth: registry.npmmirror.com/mammoth/1.5.1
|
||||
mongoose: registry.npmmirror.com/mongoose/6.10.0
|
||||
nanoid: registry.npmmirror.com/nanoid/4.0.1
|
||||
@@ -94,6 +97,7 @@ devDependencies:
|
||||
'@svgr/webpack': registry.npmmirror.com/@svgr/webpack/6.5.1
|
||||
'@types/formidable': registry.npmmirror.com/@types/formidable/2.0.5
|
||||
'@types/jsonwebtoken': registry.npmmirror.com/@types/jsonwebtoken/9.0.1
|
||||
'@types/lodash': registry.npmmirror.com/@types/lodash/4.14.191
|
||||
'@types/node': registry.npmmirror.com/@types/node/18.14.0
|
||||
'@types/nodemailer': registry.npmmirror.com/@types/nodemailer/6.4.7
|
||||
'@types/react': registry.npmmirror.com/@types/react/18.0.28
|
||||
@@ -4794,7 +4798,6 @@ packages:
|
||||
resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/lodash/-/lodash-4.14.191.tgz}
|
||||
name: '@types/lodash'
|
||||
version: 4.14.191
|
||||
dev: false
|
||||
|
||||
registry.npmmirror.com/@types/mdast/3.0.10:
|
||||
resolution: {integrity: sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/@types/mdast/-/mdast-3.0.10.tgz}
|
||||
|
@@ -37,7 +37,7 @@ function checkRes(data: ResponseDataType) {
|
||||
console.log('error->', data, 'data is empty');
|
||||
return Promise.reject('服务器异常');
|
||||
} else if (data.code < 200 || data.code >= 400) {
|
||||
return Promise.reject(data.message);
|
||||
return Promise.reject(data);
|
||||
}
|
||||
return data.data;
|
||||
}
|
||||
|
@@ -62,8 +62,8 @@ const Layout = ({ children }: { children: JSX.Element }) => {
|
||||
<Box h={'100%'} position={'fixed'} left={0} top={0} w={'80px'}>
|
||||
<Navbar navbarList={navbarList} />
|
||||
</Box>
|
||||
<Box ml={'80px'} p={7} h={'100%'}>
|
||||
<Box maxW={'1100px'} m={'auto'} h={'100%'}>
|
||||
<Box ml={'80px'} h={'100%'}>
|
||||
<Box maxW={'1100px'} m={'auto'} h={'100%'} p={7} overflowY={'auto'}>
|
||||
<Auth>{children}</Auth>
|
||||
</Box>
|
||||
</Box>
|
||||
|
@@ -1,16 +1,63 @@
|
||||
import React from 'react';
|
||||
import React, { useRef, useEffect, useMemo } from 'react';
|
||||
import type { BoxProps } from '@chakra-ui/react';
|
||||
import { Box } from '@chakra-ui/react';
|
||||
import { throttle } from 'lodash';
|
||||
|
||||
interface Props extends BoxProps {
|
||||
nextPage: () => void;
|
||||
isLoadAll: boolean;
|
||||
requesting: boolean;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const ScrollData = ({ children, nextPage, ...props }: Props) => {
|
||||
const ScrollData = ({ children, nextPage, isLoadAll, requesting, ...props }: Props) => {
|
||||
const elementRef = useRef<HTMLDivElement>(null);
|
||||
const loadText = useMemo(() => {
|
||||
if (requesting) return '请求中……';
|
||||
if (isLoadAll) return '已加载全部';
|
||||
return '点击加载更多';
|
||||
}, [isLoadAll, requesting]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!elementRef.current) return;
|
||||
|
||||
const scrolling = throttle((e: Event) => {
|
||||
const element = e.target as HTMLDivElement;
|
||||
if (!element) return;
|
||||
// 当前滚动位置
|
||||
const scrollTop = element.scrollTop;
|
||||
// 可视高度
|
||||
const clientHeight = element.clientHeight;
|
||||
// 内容总高度
|
||||
const scrollHeight = element.scrollHeight;
|
||||
// 判断是否滚动到底部
|
||||
if (scrollTop + clientHeight + 100 >= scrollHeight) {
|
||||
nextPage();
|
||||
}
|
||||
}, 100);
|
||||
elementRef.current.addEventListener('scroll', scrolling);
|
||||
return () => {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
elementRef.current?.removeEventListener('scroll', scrolling);
|
||||
};
|
||||
}, [elementRef, nextPage]);
|
||||
|
||||
return (
|
||||
<Box {...props} overflow={'auto'}>
|
||||
<Box {...props} ref={elementRef} overflow={'auto'}>
|
||||
{children}
|
||||
<Box
|
||||
mt={2}
|
||||
fontSize={'xs'}
|
||||
color={'blackAlpha.500'}
|
||||
textAlign={'center'}
|
||||
cursor={loadText === '点击加载更多' ? 'pointer' : 'default'}
|
||||
onClick={() => {
|
||||
if (loadText !== '点击加载更多') return;
|
||||
nextPage();
|
||||
}}
|
||||
>
|
||||
{loadText}
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@@ -37,6 +37,7 @@ export const usePaging = <T = any>({
|
||||
setIsLoadAll(true);
|
||||
}
|
||||
setTotal(res.total);
|
||||
setPageNum(num);
|
||||
return data;
|
||||
});
|
||||
} catch (error: any) {
|
||||
@@ -53,15 +54,18 @@ export const usePaging = <T = any>({
|
||||
[api, isLoadAll, pageSize, params, requesting, toast]
|
||||
);
|
||||
|
||||
useQuery(['init', pageNum], () => getData(pageNum, pageNum === 1));
|
||||
const nextPage = useCallback(() => getData(pageNum + 1), [getData, pageNum]);
|
||||
|
||||
useQuery(['init'], () => getData(1, true));
|
||||
|
||||
return {
|
||||
pageNum,
|
||||
pageSize,
|
||||
setPageNum,
|
||||
total,
|
||||
data,
|
||||
getData,
|
||||
requesting
|
||||
requesting,
|
||||
isLoadAll,
|
||||
nextPage
|
||||
};
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@ import axios from 'axios';
|
||||
import { connectToDatabase, User, Pay } from '@/service/mongo';
|
||||
import { authToken } from '@/service/utils/tools';
|
||||
import { PaySchema } from '@/types/mongoSchema';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
@@ -28,6 +29,10 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
`https://sif268.laf.dev/wechat-order-query?order_number=${payOrder.orderId}&api_key=${process.env.WXPAYCODE}`
|
||||
);
|
||||
|
||||
// 校验下是否超过一天
|
||||
const orderTime = dayjs(payOrder.createTime);
|
||||
const diffInHours = dayjs().diff(orderTime, 'hours');
|
||||
|
||||
if (data.trade_state === 'SUCCESS') {
|
||||
// 订单已支付
|
||||
try {
|
||||
@@ -47,7 +52,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
$inc: { balance: payOrder.price }
|
||||
});
|
||||
jsonRes(res, {
|
||||
data: 'success'
|
||||
data: '支付成功'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -56,17 +61,19 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||
});
|
||||
console.log(error);
|
||||
}
|
||||
} else if (data.trade_state === 'CLOSED') {
|
||||
} else if (data.trade_state === 'CLOSED' || diffInHours > 24) {
|
||||
// 订单已关闭
|
||||
await Pay.findByIdAndUpdate(payId, {
|
||||
status: 'CLOSED'
|
||||
});
|
||||
jsonRes(res, {
|
||||
data: '订单已过期'
|
||||
});
|
||||
} else {
|
||||
throw new Error(data.trade_state_desc);
|
||||
}
|
||||
throw new Error('订单已过期');
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
// console.log(err);
|
||||
jsonRes(res, {
|
||||
code: 500,
|
||||
error: err
|
||||
|
@@ -28,8 +28,9 @@ const ImportDataModal = dynamic(() => import('./components/ImportDataModal'));
|
||||
|
||||
const DataList = () => {
|
||||
const {
|
||||
setPageNum,
|
||||
pageNum,
|
||||
nextPage,
|
||||
isLoadAll,
|
||||
requesting,
|
||||
data: dataList,
|
||||
getData
|
||||
} = usePaging<DataListItem>({
|
||||
@@ -75,7 +76,7 @@ const DataList = () => {
|
||||
</Card>
|
||||
{/* 数据表 */}
|
||||
<Card mt={3} flex={'1 0 0'} h={['auto', '0']} px={6} py={4}>
|
||||
<ScrollData h={'100%'} nextPage={() => setPageNum(pageNum + 1)}>
|
||||
<ScrollData h={'100%'} nextPage={nextPage} isLoadAll={isLoadAll} requesting={requesting}>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
|
@@ -32,6 +32,7 @@ import { PaySchema } from '@/types/mongoSchema';
|
||||
import dayjs from 'dayjs';
|
||||
import { formatPrice } from '@/utils/user';
|
||||
import WxConcat from '@/components/WxConcat';
|
||||
import ScrollData from '@/components/ScrollData';
|
||||
|
||||
const PayModal = dynamic(() => import('./components/PayModal'));
|
||||
|
||||
@@ -52,7 +53,12 @@ const NumberSetting = () => {
|
||||
control,
|
||||
name: 'accounts'
|
||||
});
|
||||
const { setPageNum, data: bills } = usePaging<UserBillType>({
|
||||
const {
|
||||
nextPage,
|
||||
isLoadAll,
|
||||
requesting,
|
||||
data: bills
|
||||
} = usePaging<UserBillType>({
|
||||
api: getUserBills,
|
||||
pageSize: 30
|
||||
});
|
||||
@@ -84,9 +90,14 @@ const NumberSetting = () => {
|
||||
|
||||
const handleRefreshPayOrder = useCallback(
|
||||
async (payId: string) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
await checkPayResult(payId);
|
||||
|
||||
try {
|
||||
const data = await checkPayResult(payId);
|
||||
toast({
|
||||
title: data,
|
||||
status: 'info'
|
||||
});
|
||||
const res = await getPayOrders();
|
||||
setPayOrders(res);
|
||||
} catch (error: any) {
|
||||
@@ -96,6 +107,7 @@ const NumberSetting = () => {
|
||||
});
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
},
|
||||
[setLoading, toast]
|
||||
@@ -196,8 +208,8 @@ const NumberSetting = () => {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
<Card mt={6} px={6} py={4}>
|
||||
<Flex alignItems={'flex-end'}>
|
||||
<Card mt={6} py={4}>
|
||||
<Flex alignItems={'flex-end'} px={6} mb={1}>
|
||||
<Box fontSize={'xl'} fontWeight={'bold'}>
|
||||
充值记录
|
||||
</Box>
|
||||
@@ -205,7 +217,7 @@ const NumberSetting = () => {
|
||||
异常问题,wx联系
|
||||
</Button>
|
||||
</Flex>
|
||||
<TableContainer maxH={'400px'} overflowY={'auto'}>
|
||||
<TableContainer maxH={'400px'} overflowY={'auto'} px={6}>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
@@ -240,11 +252,18 @@ const NumberSetting = () => {
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
<Card mt={6} px={6} py={4}>
|
||||
<Box fontSize={'xl'} fontWeight={'bold'}>
|
||||
使用记录(最新30条)
|
||||
<Card mt={6} py={4}>
|
||||
<Box fontSize={'xl'} fontWeight={'bold'} px={6} mb={1}>
|
||||
使用记录
|
||||
</Box>
|
||||
<TableContainer maxH={'400px'} overflowY={'auto'}>
|
||||
<ScrollData
|
||||
maxH={'400px'}
|
||||
px={6}
|
||||
isLoadAll={isLoadAll}
|
||||
requesting={requesting}
|
||||
nextPage={nextPage}
|
||||
>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
@@ -266,6 +285,7 @@ const NumberSetting = () => {
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</ScrollData>
|
||||
</Card>
|
||||
{showPay && <PayModal onClose={() => setShowPay(false)} />}
|
||||
{/* wx 联系 */}
|
||||
|
Reference in New Issue
Block a user