mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-07 01:02:55 +08:00
perf: page ui (#5469)
* perf: page ui * fix: icon * limit chat items * limit chat items
This commit is contained in:
@@ -60,9 +60,10 @@ const BillTable = () => {
|
||||
isLoading,
|
||||
Pagination,
|
||||
getData,
|
||||
total
|
||||
total,
|
||||
pageSize
|
||||
} = usePagination(getBills, {
|
||||
pageSize: 20,
|
||||
defaultPageSize: 20,
|
||||
params: {
|
||||
type: billType
|
||||
},
|
||||
@@ -95,8 +96,8 @@ const BillTable = () => {
|
||||
}, [billType]);
|
||||
|
||||
return (
|
||||
<MyBox isLoading={isLoading} position={'relative'} h={'100%'} minH={'50vh'}>
|
||||
<TableContainer>
|
||||
<MyBox isLoading={isLoading} display={'flex'} flexDir={'column'} h={'100%'}>
|
||||
<TableContainer flex={'1 0 0'} h={0} overflowY={'auto'}>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
@@ -147,11 +148,6 @@ const BillTable = () => {
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
{total >= 20 && (
|
||||
<Flex mt={3} justifyContent={'flex-end'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
{!isLoading && bills.length === 0 && (
|
||||
<Flex
|
||||
mt={'20vh'}
|
||||
@@ -167,6 +163,11 @@ const BillTable = () => {
|
||||
)}
|
||||
</TableContainer>
|
||||
|
||||
{total >= pageSize && (
|
||||
<Flex mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
{!!billDetail && (
|
||||
<BillDetailModal bill={billDetail} onClose={() => setBillDetail(undefined)} />
|
||||
)}
|
||||
|
||||
@@ -32,14 +32,15 @@ const InvoiceTable = () => {
|
||||
data: invoices,
|
||||
isLoading,
|
||||
Pagination,
|
||||
total
|
||||
total,
|
||||
pageSize
|
||||
} = usePagination(getInvoiceRecords, {
|
||||
pageSize: 20
|
||||
defaultPageSize: 10
|
||||
});
|
||||
|
||||
return (
|
||||
<MyBox isLoading={isLoading} position={'relative'} h={'100%'} overflow={'overlay'}>
|
||||
<TableContainer minH={'50vh'}>
|
||||
<MyBox isLoading={isLoading} position={'relative'} minH={'50vh'} overflow={'overlay'}>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead h="3rem">
|
||||
<Tr>
|
||||
@@ -101,11 +102,6 @@ const InvoiceTable = () => {
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
{total >= 20 && (
|
||||
<Flex mt={3} justifyContent={'flex-end'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
{!isLoading && invoices.length === 0 && (
|
||||
<Flex
|
||||
mt={'20vh'}
|
||||
@@ -120,6 +116,11 @@ const InvoiceTable = () => {
|
||||
</Flex>
|
||||
)}
|
||||
</TableContainer>
|
||||
{total >= pageSize && (
|
||||
<Flex mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
{!!invoiceDetailData && (
|
||||
<InvoiceDetailModal invoice={invoiceDetailData} onClose={() => setInvoiceDetailData('')} />
|
||||
)}
|
||||
|
||||
@@ -68,7 +68,7 @@ const UsageTableList = ({
|
||||
Pagination,
|
||||
total
|
||||
} = usePagination(getUserUsages, {
|
||||
pageSize: 20,
|
||||
defaultPageSize: 20,
|
||||
params: requestParams,
|
||||
refreshDeps: [requestParams]
|
||||
});
|
||||
@@ -111,7 +111,7 @@ const UsageTableList = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MyBox display={'flex'} flexDirection={'column'} h={'100%'} isLoading={isLoading}>
|
||||
<Box>{Tabs}</Box>
|
||||
<Flex mt={4} w={'100%'}>
|
||||
<Box>{Selectors}</Box>
|
||||
@@ -123,54 +123,46 @@ const UsageTableList = ({
|
||||
onConfirm={exportUsage}
|
||||
/>
|
||||
</Flex>
|
||||
<MyBox mt={3} flex={'1 0 0'} h={0} isLoading={isLoading}>
|
||||
<Box h={'100%'} overflow={'auto'}>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('common:user.Time')}</Th>
|
||||
<Th>{t('account_usage:member')}</Th>
|
||||
<Th>{t('account_usage:user_type')}</Th>
|
||||
<Th>{t('account_usage:project_name')}</Th>
|
||||
<Th>{t('account_usage:total_points')}</Th>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody fontSize={'sm'}>
|
||||
{usages.map((item) => (
|
||||
<Tr key={item.id}>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} color={'myGray.500'}>
|
||||
<Avatar src={item.sourceMember.avatar} w={'20px'} mr={1} rounded={'full'} />
|
||||
{item.sourceMember.name}
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>{t(UsageSourceMap[item.source]?.label as any) || '-'}</Td>
|
||||
<Td className="textEllipsis" maxW={'400px'} title={t(item.appName as any)}>
|
||||
{t(item.appName as any) || '-'}
|
||||
</Td>
|
||||
<Td>{formatNumber(item.totalPoints) || 0}</Td>
|
||||
<Td>
|
||||
<Button
|
||||
size={'sm'}
|
||||
variant={'whitePrimary'}
|
||||
onClick={() => setUsageDetail(item)}
|
||||
>
|
||||
{t('account_usage:details')}
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
{!isLoading && usages.length === 0 && (
|
||||
<EmptyTip text={t('account_usage:no_usage_records')}></EmptyTip>
|
||||
)}
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</MyBox>
|
||||
<TableContainer mt={3} flex={'1 0 0'} h={0} overflowY={'auto'}>
|
||||
<Table>
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th>{t('common:user.Time')}</Th>
|
||||
<Th>{t('account_usage:member')}</Th>
|
||||
<Th>{t('account_usage:user_type')}</Th>
|
||||
<Th>{t('account_usage:project_name')}</Th>
|
||||
<Th>{t('account_usage:total_points')}</Th>
|
||||
<Th></Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody fontSize={'sm'}>
|
||||
{usages.map((item) => (
|
||||
<Tr key={item.id}>
|
||||
<Td>{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')}</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} color={'myGray.500'}>
|
||||
<Avatar src={item.sourceMember.avatar} w={'20px'} mr={1} rounded={'full'} />
|
||||
{item.sourceMember.name}
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>{t(UsageSourceMap[item.source]?.label as any) || '-'}</Td>
|
||||
<Td className="textEllipsis" maxW={'400px'} title={t(item.appName as any)}>
|
||||
{t(item.appName as any) || '-'}
|
||||
</Td>
|
||||
<Td>{formatNumber(item.totalPoints) || 0}</Td>
|
||||
<Td>
|
||||
<Button size={'sm'} variant={'whitePrimary'} onClick={() => setUsageDetail(item)}>
|
||||
{t('account_usage:details')}
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
{!isLoading && usages.length === 0 && (
|
||||
<EmptyTip text={t('account_usage:no_usage_records')}></EmptyTip>
|
||||
)}
|
||||
</TableContainer>
|
||||
<Flex mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
@@ -178,7 +170,7 @@ const UsageTableList = ({
|
||||
{!!usageDetail && (
|
||||
<UsageDetail usage={usageDetail} onClose={() => setUsageDetail(undefined)} />
|
||||
)}
|
||||
</>
|
||||
</MyBox>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ import {
|
||||
} from '@fastgpt/global/core/app/logs/constants';
|
||||
import { formatDateByTimespan } from '@fastgpt/global/core/app/logs/utils';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
|
||||
export type HeaderControlProps = {
|
||||
appId: string;
|
||||
@@ -149,7 +150,7 @@ const LogChart = ({
|
||||
|
||||
const [offset, setOffset] = useState<string>(offsetOptions[0].value);
|
||||
|
||||
const { data: chartData } = useRequest2(
|
||||
const { data: chartData, loading } = useRequest2(
|
||||
async () => {
|
||||
return getAppChartData({
|
||||
appId,
|
||||
@@ -331,7 +332,7 @@ const LogChart = ({
|
||||
]);
|
||||
|
||||
return (
|
||||
<Flex flexDir={'column'} h={'full'}>
|
||||
<MyBox isLoading={loading} display={'flex'} flexDir={'column'} h={'full'}>
|
||||
<HeaderControl
|
||||
appId={appId}
|
||||
chatSources={chatSources}
|
||||
@@ -751,7 +752,7 @@ const LogChart = ({
|
||||
</AccordionItem>
|
||||
</Accordion>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</MyBox>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ import EmptyTip from '@fastgpt/web/components/common/EmptyTip';
|
||||
import dynamic from 'next/dynamic';
|
||||
import type { HeaderControlProps } from './LogChart';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import MyBox from '@fastgpt/web/components/common/MyBox';
|
||||
|
||||
const DetailLogsModal = dynamic(() => import('./DetailLogsModal'));
|
||||
|
||||
@@ -196,9 +197,10 @@ const LogTable = ({
|
||||
Pagination,
|
||||
getData,
|
||||
pageNum,
|
||||
total
|
||||
total,
|
||||
pageSize
|
||||
} = usePagination(getAppChatLogs, {
|
||||
pageSize: 20,
|
||||
defaultPageSize: 20,
|
||||
params,
|
||||
refreshDeps: [params]
|
||||
});
|
||||
@@ -338,7 +340,7 @@ const LogTable = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<Flex flexDir={'column'} h={'full'} overflow={'auto'} px={[4, 8]}>
|
||||
<MyBox isLoading={isLoading} display={'flex'} flexDir={'column'} h={'full'} px={[4, 8]}>
|
||||
<Flex alignItems={'center'} gap={3} flexWrap={'wrap'}>
|
||||
{showSourceSelector && (
|
||||
<Flex>
|
||||
@@ -465,7 +467,7 @@ const LogTable = ({
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<TableContainer mt={[2, 4]} flex={['', '1 0 0']} h={['auto', 0]} overflowY={'auto'}>
|
||||
<TableContainer mt={[2, 4]} flex={'1 0 0'} overflowY={'auto'}>
|
||||
<Table variant={'simple'} fontSize={'sm'}>
|
||||
<Thead>
|
||||
<Tr>
|
||||
@@ -496,9 +498,11 @@ const LogTable = ({
|
||||
{logs.length === 0 && !isLoading && <EmptyTip text={t('app:logs_empty')}></EmptyTip>}
|
||||
</TableContainer>
|
||||
|
||||
<HStack w={'100%'} mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</HStack>
|
||||
{total >= pageSize && (
|
||||
<Flex mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
{!!detailLogsId && (
|
||||
<DetailLogsModal
|
||||
@@ -510,7 +514,7 @@ const LogTable = ({
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
</MyBox>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -149,11 +149,12 @@ const Header = () => {
|
||||
p={0.5}
|
||||
borderRadius={'sm'}
|
||||
>
|
||||
<MyIcon
|
||||
name={'common/leftArrowLight'}
|
||||
w={6}
|
||||
cursor={'pointer'}
|
||||
onClick={isSaved ? onBack : onOpenBackConfirm}
|
||||
<IconButton
|
||||
icon={<MyIcon name={'common/leftArrowLight'} color={'myGray.600'} w={'0.8rem'} />}
|
||||
aria-label={''}
|
||||
size={'xs'}
|
||||
w={'1rem'}
|
||||
variant={'ghost'}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -213,8 +214,6 @@ const Header = () => {
|
||||
isPc,
|
||||
currentTab,
|
||||
isSaved,
|
||||
onBack,
|
||||
onOpenBackConfirm,
|
||||
isV2Workflow,
|
||||
t,
|
||||
showHistoryModal,
|
||||
|
||||
@@ -149,11 +149,12 @@ const Header = () => {
|
||||
p={0.5}
|
||||
borderRadius={'sm'}
|
||||
>
|
||||
<MyIcon
|
||||
name={'common/leftArrowLight'}
|
||||
w={6}
|
||||
cursor={'pointer'}
|
||||
onClick={isSaved ? onBack : onOpenBackConfirm}
|
||||
<IconButton
|
||||
icon={<MyIcon name={'common/leftArrowLight'} color={'myGray.600'} w={'0.8rem'} />}
|
||||
aria-label={''}
|
||||
size={'xs'}
|
||||
w={'1rem'}
|
||||
variant={'ghost'}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -213,8 +214,6 @@ const Header = () => {
|
||||
isPc,
|
||||
currentTab,
|
||||
isSaved,
|
||||
onBack,
|
||||
onOpenBackConfirm,
|
||||
isV2Workflow,
|
||||
t,
|
||||
showHistoryModal,
|
||||
|
||||
@@ -97,9 +97,11 @@ const EvaluationDetailModal = ({
|
||||
const {
|
||||
data: evalItemsList,
|
||||
Pagination,
|
||||
pageSize,
|
||||
total,
|
||||
getData: fetchData
|
||||
} = usePagination(getEvalItemsList, {
|
||||
pageSize: 10,
|
||||
defaultPageSize: 20,
|
||||
params: {
|
||||
evalId: evalDetail._id
|
||||
},
|
||||
@@ -440,9 +442,11 @@ const EvaluationDetailModal = ({
|
||||
})}
|
||||
</Box>
|
||||
|
||||
<Box px={6} py={3}>
|
||||
<Pagination />
|
||||
</Box>
|
||||
{total >= pageSize && (
|
||||
<Flex my={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
{evalItem ? (
|
||||
|
||||
@@ -128,7 +128,7 @@ const CollectionPageContextProvider = ({ children }: { children: ReactNode }) =>
|
||||
pageNum,
|
||||
pageSize
|
||||
} = usePagination(getDatasetCollections, {
|
||||
pageSize: 20,
|
||||
defaultPageSize: 20,
|
||||
params: {
|
||||
datasetId,
|
||||
parentId,
|
||||
|
||||
@@ -10,14 +10,16 @@ import {
|
||||
Td,
|
||||
Tbody,
|
||||
MenuButton,
|
||||
Switch
|
||||
Switch,
|
||||
Checkbox,
|
||||
HStack,
|
||||
Button
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
delDatasetCollectionById,
|
||||
putDatasetCollectionById,
|
||||
postLinkCollectionSync
|
||||
} from '@/web/core/dataset/api';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { useConfirm } from '@fastgpt/web/hooks/useConfirm';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import MyIcon from '@fastgpt/web/components/common/Icon';
|
||||
@@ -49,6 +51,7 @@ import { useFolderDrag } from '@/components/common/folder/useFolderDrag';
|
||||
import TagsPopOver from './TagsPopOver';
|
||||
import { useSystemStore } from '@/web/common/system/useSystemStore';
|
||||
import TrainingStates from './TrainingStates';
|
||||
import { useTableMultipleSelect } from '@fastgpt/web/hooks/useTableMultipleSelect';
|
||||
|
||||
const Header = dynamic(() => import('./Header'));
|
||||
const EmptyCollectionTip = dynamic(() => import('./EmptyCollectionTip'));
|
||||
@@ -103,6 +106,19 @@ const CollectionCard = () => {
|
||||
[collections, t]
|
||||
);
|
||||
|
||||
const {
|
||||
selectedItems,
|
||||
toggleSelect,
|
||||
isSelected,
|
||||
setSelectedItems,
|
||||
FloatingActionBar,
|
||||
isSelecteAll,
|
||||
selectAllTrigger
|
||||
} = useTableMultipleSelect({
|
||||
list: formatCollections,
|
||||
getItemId: (e) => e._id
|
||||
});
|
||||
|
||||
const [moveCollectionData, setMoveCollectionData] = useState<{ collectionId: string }>();
|
||||
|
||||
const { onOpenModal: onOpenEditTitleModal, EditModal: EditTitleModal } = useEditTitle({
|
||||
@@ -123,9 +139,9 @@ const CollectionCard = () => {
|
||||
type: 'delete'
|
||||
});
|
||||
const { runAsync: onDelCollection } = useRequest2(
|
||||
(collectionId: string) => {
|
||||
(collectionIds: string[]) => {
|
||||
return delDatasetCollectionById({
|
||||
id: collectionId
|
||||
collectionIds
|
||||
});
|
||||
},
|
||||
{
|
||||
@@ -156,18 +172,17 @@ const CollectionCard = () => {
|
||||
[formatCollections]
|
||||
);
|
||||
|
||||
useQuery(
|
||||
['refreshCollection'],
|
||||
() => {
|
||||
useRequest2(
|
||||
async () => {
|
||||
if (!hasTrainingData && datasetDetail.status === DatasetStatusEnum.active) return;
|
||||
getData(pageNum);
|
||||
if (datasetDetail.status !== DatasetStatusEnum.active) {
|
||||
loadDatasetDetail(datasetDetail._id);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
{
|
||||
refetchInterval: 6000,
|
||||
enabled: hasTrainingData || datasetDetail.status !== DatasetStatusEnum.active
|
||||
retryInterval: 6000,
|
||||
refreshDeps: [hasTrainingData, datasetDetail.status]
|
||||
}
|
||||
);
|
||||
|
||||
@@ -186,21 +201,25 @@ const CollectionCard = () => {
|
||||
}
|
||||
});
|
||||
|
||||
const isLoading =
|
||||
isUpdating || isSyncing || (isGetting && collections.length === 0) || isDropping;
|
||||
const isLoading = isUpdating || isSyncing || isGetting || isDropping;
|
||||
|
||||
return (
|
||||
<MyBox isLoading={isLoading} h={'100%'} py={[2, 4]}>
|
||||
<MyBox isLoading={isLoading} h={'100%'} py={[2, 4]} overflow={'hidden'}>
|
||||
<Flex ref={BoxRef} flexDirection={'column'} py={[1, 0]} h={'100%'} px={[2, 6]}>
|
||||
{/* header */}
|
||||
<Header hasTrainingData={hasTrainingData} />
|
||||
|
||||
{/* collection table */}
|
||||
<TableContainer mt={3} overflowY={'auto'} fontSize={'sm'}>
|
||||
<TableContainer mt={3} overflowY={'auto'} fontSize={'sm'} flex={'1 0 0'} h={0}>
|
||||
<Table variant={'simple'} draggable={false}>
|
||||
<Thead draggable={false}>
|
||||
<Tr>
|
||||
<Th py={4}>{t('common:Name')}</Th>
|
||||
<Th py={4}>
|
||||
<HStack>
|
||||
<Checkbox isChecked={isSelecteAll} onChange={selectAllTrigger} />
|
||||
<Box>{t('common:Name')}</Box>
|
||||
</HStack>
|
||||
</Th>
|
||||
<Th py={4}>{t('dataset:collection.training_type')}</Th>
|
||||
<Th py={4}>{t('dataset:collection_data_count')}</Th>
|
||||
<Th py={4}>{t('dataset:collection.Create update time')}</Th>
|
||||
@@ -241,17 +260,27 @@ const CollectionCard = () => {
|
||||
}}
|
||||
>
|
||||
<Td minW={'150px'} maxW={['200px', '300px']} draggable py={2}>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={collection.icon as any} w={'1.25rem'} mr={2} />
|
||||
<MyTooltip label={t('common:click_drag_tip')} shouldWrapChildren={false}>
|
||||
<Box color={'myGray.900'} fontWeight={'500'} className="textEllipsis">
|
||||
{collection.name}
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
{feConfigs?.isPlus && !!collection.tags?.length && (
|
||||
<TagsPopOver currentCollection={collection} />
|
||||
)}
|
||||
<HStack>
|
||||
<Box onClick={(e) => e.stopPropagation()}>
|
||||
<Checkbox
|
||||
isChecked={isSelected(collection)}
|
||||
onChange={(e) => toggleSelect(collection)}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
<Flex alignItems={'center'}>
|
||||
<MyIcon name={collection.icon as any} w={'1.25rem'} mr={2} />
|
||||
<MyTooltip label={t('common:click_drag_tip')} shouldWrapChildren={false}>
|
||||
<Box color={'myGray.900'} fontWeight={'500'} className="textEllipsis">
|
||||
{collection.name}
|
||||
</Box>
|
||||
</MyTooltip>
|
||||
</Flex>
|
||||
{feConfigs?.isPlus && !!collection.tags?.length && (
|
||||
<TagsPopOver currentCollection={collection} />
|
||||
)}
|
||||
</Box>
|
||||
</HStack>
|
||||
</Td>
|
||||
<Td py={2}>
|
||||
{collection.trainingType
|
||||
@@ -394,7 +423,7 @@ const CollectionCard = () => {
|
||||
type: 'danger',
|
||||
onClick: () =>
|
||||
openDeleteConfirm(
|
||||
() => onDelCollection(collection._id),
|
||||
() => onDelCollection([collection._id]),
|
||||
undefined,
|
||||
collection.type === DatasetCollectionTypeEnum.folder
|
||||
? t('common:dataset.collections.Confirm to delete the folder')
|
||||
@@ -411,13 +440,39 @@ const CollectionCard = () => {
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
|
||||
{total === 0 && <EmptyCollectionTip />}
|
||||
</TableContainer>
|
||||
|
||||
<FloatingActionBar
|
||||
Controler={
|
||||
<HStack>
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
onClick={() =>
|
||||
openDeleteConfirm(
|
||||
() =>
|
||||
onDelCollection(selectedItems.map((e) => e._id)).then(() =>
|
||||
setSelectedItems([])
|
||||
),
|
||||
undefined,
|
||||
t('dataset:confirm_delete_collection', {
|
||||
num: selectedItems.length
|
||||
})
|
||||
)()
|
||||
}
|
||||
>
|
||||
{t('dataset:batch_delete')}
|
||||
</Button>
|
||||
</HStack>
|
||||
}
|
||||
>
|
||||
{total > pageSize && (
|
||||
<Flex mt={2} justifyContent={'center'}>
|
||||
<Flex justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
{total === 0 && <EmptyCollectionTip />}
|
||||
</TableContainer>
|
||||
</FloatingActionBar>
|
||||
|
||||
<ConfirmDeleteModal />
|
||||
<ConfirmSyncModal />
|
||||
|
||||
@@ -27,9 +27,10 @@ const BillAndInvoice = () => {
|
||||
|
||||
return (
|
||||
<AccountContainer>
|
||||
<Box p={['1rem', '2rem']}>
|
||||
<Flex h={'100%'} flexDirection={'column'} p={['2', '4']}>
|
||||
<Flex justifyContent={'space-between'} alignItems={'center'} pb={'0.75rem'}>
|
||||
<FillRowTabs
|
||||
py={1}
|
||||
list={[
|
||||
{ label: t('account_bill:bill_record'), value: InvoiceTabEnum.bill },
|
||||
{
|
||||
@@ -61,7 +62,7 @@ const BillAndInvoice = () => {
|
||||
</Button>
|
||||
)}
|
||||
</Flex>
|
||||
<Box h={'100%'}>
|
||||
<Box flex={'1 0 0'} h={0} overflow={'auto'}>
|
||||
{invoiceTab === InvoiceTabEnum.bill && <BillTable />}
|
||||
{invoiceTab === InvoiceTabEnum.invoice && <InvoiceTable />}
|
||||
{invoiceTab === InvoiceTabEnum.invoiceHeader && <InvoiceHeaderForm />}
|
||||
@@ -73,7 +74,7 @@ const BillAndInvoice = () => {
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
</AccountContainer>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ const InformTable = () => {
|
||||
getData,
|
||||
pageNum
|
||||
} = usePagination(getInforms, {
|
||||
pageSize: 20
|
||||
defaultPageSize: 20
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -147,7 +147,7 @@ const InformTable = () => {
|
||||
)}
|
||||
|
||||
{total > pageSize && (
|
||||
<Flex w="100%" mt={4} px={[3, 8]} justifyContent="flex-end">
|
||||
<Flex mt={4} justifyContent="center">
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -43,7 +43,7 @@ const Promotion = () => {
|
||||
pageSize,
|
||||
Pagination
|
||||
} = usePagination(getPromotionRecords, {
|
||||
pageSize: 20
|
||||
defaultPageSize: 20
|
||||
});
|
||||
|
||||
const { data: { invitedAmount = 0, earningsAmount = 0 } = {} } = useQuery(
|
||||
@@ -131,7 +131,7 @@ const Promotion = () => {
|
||||
<EmptyTip text={t('account_promotion:no_invite_records')}></EmptyTip>
|
||||
)}
|
||||
{total > pageSize && (
|
||||
<Flex mt={4} justifyContent={'flex-end'}>
|
||||
<Flex mt={3} justifyContent={'center'}>
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { MongoAppChatLog } from '@fastgpt/service/core/app/logs/chatLogsSchema';
|
||||
import { DispatchNodeResponseKeyEnum } from '@fastgpt/global/core/workflow/runtime/constants';
|
||||
import { addLog } from '@fastgpt/service/common/system/log';
|
||||
import type { ChatSchemaType } from '@fastgpt/global/core/chat/type';
|
||||
import { surrenderProcess } from '@fastgpt/service/common/system/tools';
|
||||
|
||||
export type SyncAppChatLogQuery = {};
|
||||
|
||||
@@ -63,7 +64,9 @@ async function handler(
|
||||
|
||||
async function processChatRecord(chat: ChatSchemaType) {
|
||||
async function calculateChatItemStats() {
|
||||
const chatItems = await MongoChatItem.find({ appId: chat.appId, chatId: chat.chatId }).lean();
|
||||
const chatItems = await MongoChatItem.find({ appId: chat.appId, chatId: chat.chatId })
|
||||
.limit(1000)
|
||||
.lean();
|
||||
|
||||
let chatItemCount = chatItems.length;
|
||||
let errorCount = 0;
|
||||
@@ -73,6 +76,8 @@ async function processChatRecord(chat: ChatSchemaType) {
|
||||
let totalResponseTime = 0;
|
||||
|
||||
for (const item of chatItems) {
|
||||
await surrenderProcess();
|
||||
|
||||
const itemData = item as any;
|
||||
|
||||
if (itemData.userGoodFeedback && itemData.userGoodFeedback.trim() !== '') {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { NextApiRequest } from 'next';
|
||||
import { findCollectionAndChild } from '@fastgpt/service/core/dataset/collection/utils';
|
||||
import { delCollection } from '@fastgpt/service/core/dataset/collection/controller';
|
||||
import { authDatasetCollection } from '@fastgpt/service/support/permission/dataset/auth';
|
||||
@@ -9,28 +8,50 @@ import { CommonErrEnum } from '@fastgpt/global/common/error/code/common';
|
||||
import { addAuditLog } from '@fastgpt/service/support/user/audit/util';
|
||||
import { AuditEventEnum } from '@fastgpt/global/support/user/audit/constants';
|
||||
import { getI18nDatasetType } from '@fastgpt/service/support/user/audit/util';
|
||||
import type { ApiRequestProps } from '@fastgpt/service/type/next';
|
||||
|
||||
async function handler(req: NextApiRequest) {
|
||||
const { id: collectionId } = req.query as { id: string };
|
||||
export type DelCollectionBody = {
|
||||
collectionIds: string[];
|
||||
};
|
||||
|
||||
if (!collectionId) {
|
||||
async function handler(req: ApiRequestProps<DelCollectionBody>) {
|
||||
const { collectionIds } = req.body;
|
||||
|
||||
if (!collectionIds) {
|
||||
return Promise.reject(CommonErrEnum.missingParams);
|
||||
}
|
||||
|
||||
const { teamId, collection, tmbId } = await authDatasetCollection({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
collectionId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
const [{ teamId, collection, tmbId }] = await Promise.all(
|
||||
collectionIds.map(async (collectionId) => {
|
||||
return await authDatasetCollection({
|
||||
req,
|
||||
authToken: true,
|
||||
authApiKey: true,
|
||||
collectionId,
|
||||
per: WritePermissionVal
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// find all delete id
|
||||
const collections = await findCollectionAndChild({
|
||||
teamId,
|
||||
datasetId: collection.datasetId,
|
||||
collectionId,
|
||||
fields: '_id teamId datasetId fileId metadata'
|
||||
const collections = await Promise.all(
|
||||
collectionIds.map(async (collectionId) => {
|
||||
return await findCollectionAndChild({
|
||||
teamId,
|
||||
datasetId: collection.datasetId,
|
||||
collectionId,
|
||||
fields: '_id teamId datasetId fileId metadata'
|
||||
});
|
||||
})
|
||||
).then((res) => {
|
||||
const flattened = res.flat();
|
||||
console.log(flattened.length, 22);
|
||||
// Remove duplicates based on _id
|
||||
const uniqueCollections = flattened.filter(
|
||||
(collection, index, arr) =>
|
||||
arr.findIndex((item) => item._id.toString() === collection._id.toString()) === index
|
||||
);
|
||||
return uniqueCollections;
|
||||
});
|
||||
|
||||
// delete
|
||||
|
||||
@@ -23,7 +23,7 @@ async function handler(req: NextApiRequest) {
|
||||
simple = false
|
||||
} = req.body as any;
|
||||
searchText = searchText?.replace(/'/g, '');
|
||||
pageSize = Math.min(pageSize, 30);
|
||||
pageSize = Math.min(pageSize, 100);
|
||||
|
||||
// auth dataset and get my role
|
||||
const { teamId, permission } = await authDataset({
|
||||
|
||||
@@ -28,7 +28,7 @@ async function handler(
|
||||
simple = false
|
||||
} = req.body as GetDatasetCollectionsProps;
|
||||
let { pageSize, offset } = parsePaginationRequest(req);
|
||||
pageSize = Math.min(pageSize, 30);
|
||||
pageSize = Math.min(pageSize, 100);
|
||||
searchText = searchText?.replace(/'/g, '');
|
||||
|
||||
// auth dataset and get my role
|
||||
|
||||
@@ -46,9 +46,11 @@ const Evaluation = () => {
|
||||
const {
|
||||
data: evaluationList,
|
||||
Pagination,
|
||||
getData: fetchData
|
||||
getData: fetchData,
|
||||
total,
|
||||
pageSize
|
||||
} = usePagination(getEvaluationList, {
|
||||
pageSize: 20,
|
||||
defaultPageSize: 20,
|
||||
pollingInterval,
|
||||
pollingWhenHidden: true,
|
||||
params: {
|
||||
@@ -185,90 +187,90 @@ const Evaluation = () => {
|
||||
<Flex h={'full'} bg={'white'} p={6} flexDirection="column">
|
||||
{renderHeader(MenuIcon)}
|
||||
|
||||
<MyBox flex={'1 0 0'} overflow="auto">
|
||||
<TableContainer mt={3} fontSize={'sm'}>
|
||||
<Table variant={'simple'}>
|
||||
<Thead>
|
||||
<Tr color={'myGray.600'}>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Task_name')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Progress')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Executor')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Evaluation_app')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Start_end_time')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Overall_score')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Action')}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr h={'5px'} />
|
||||
{evaluationList.map((item) => {
|
||||
return (
|
||||
<Tr key={item._id}>
|
||||
<Td fontWeight={'medium'} color={'myGray.900'}>
|
||||
{item.name}
|
||||
</Td>
|
||||
<Td>{renderProgress(item)}</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} gap={1.5}>
|
||||
<Avatar
|
||||
src={item.executorAvatar}
|
||||
w={5}
|
||||
borderRadius={'full'}
|
||||
border={'1px solid'}
|
||||
borderColor={'myGray.200'}
|
||||
/>
|
||||
<Box color={'myGray.900'}>{item.executorName}</Box>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} gap={1.5}>
|
||||
<Avatar src={item.appAvatar} w={5} borderRadius={'4px'} />
|
||||
<Box color={'myGray.900'}>{item.appName}</Box>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td color={'myGray.900'}>
|
||||
<Box>{formatTime2YMDHM(item.createTime)}</Box>
|
||||
<Box>{formatTime2YMDHM(item.finishTime)}</Box>
|
||||
</Td>
|
||||
<Td color={item.score ? 'myGray.600' : 'myGray.900'}>
|
||||
{typeof item.score === 'number' ? (item.score * 100).toFixed(2) : '-'}
|
||||
</Td>
|
||||
<Td>
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
leftIcon={<MyIcon name={'common/detail'} w={4} />}
|
||||
fontSize={'12px'}
|
||||
fontWeight={'medium'}
|
||||
mr={2}
|
||||
onClick={() => setEvalDetailId(item._id)}
|
||||
>
|
||||
{t('dashboard_evaluation:detail')}
|
||||
</Button>
|
||||
|
||||
<PopoverConfirm
|
||||
type="delete"
|
||||
Trigger={
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
size={'mdSquare'}
|
||||
variant={'whiteDanger'}
|
||||
icon={<MyIcon name={'delete'} w={4} />}
|
||||
/>
|
||||
}
|
||||
content={t('dashboard_evaluation:comfirm_delete_task')}
|
||||
onConfirm={() => onDeleteEval({ evalId: item._id })}
|
||||
<TableContainer mt={3} fontSize={'sm'} flex={'1 0 0'} overflowY="auto">
|
||||
<Table variant={'simple'}>
|
||||
<Thead>
|
||||
<Tr color={'myGray.600'}>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Task_name')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Progress')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Executor')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Evaluation_app')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Start_end_time')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Overall_score')}</Th>
|
||||
<Th fontWeight={'400'}>{t('dashboard_evaluation:Action')}</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
<Tr h={'5px'} />
|
||||
{evaluationList.map((item) => {
|
||||
return (
|
||||
<Tr key={item._id}>
|
||||
<Td fontWeight={'medium'} color={'myGray.900'}>
|
||||
{item.name}
|
||||
</Td>
|
||||
<Td>{renderProgress(item)}</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} gap={1.5}>
|
||||
<Avatar
|
||||
src={item.executorAvatar}
|
||||
w={5}
|
||||
borderRadius={'full'}
|
||||
border={'1px solid'}
|
||||
borderColor={'myGray.200'}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</MyBox>
|
||||
<Flex mt={4} justifyContent="center">
|
||||
<Pagination />
|
||||
</Flex>
|
||||
<Box color={'myGray.900'}>{item.executorName}</Box>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td>
|
||||
<Flex alignItems={'center'} gap={1.5}>
|
||||
<Avatar src={item.appAvatar} w={5} borderRadius={'4px'} />
|
||||
<Box color={'myGray.900'}>{item.appName}</Box>
|
||||
</Flex>
|
||||
</Td>
|
||||
<Td color={'myGray.900'}>
|
||||
<Box>{formatTime2YMDHM(item.createTime)}</Box>
|
||||
<Box>{formatTime2YMDHM(item.finishTime)}</Box>
|
||||
</Td>
|
||||
<Td color={item.score ? 'myGray.600' : 'myGray.900'}>
|
||||
{typeof item.score === 'number' ? (item.score * 100).toFixed(2) : '-'}
|
||||
</Td>
|
||||
<Td>
|
||||
<Button
|
||||
variant={'whiteBase'}
|
||||
leftIcon={<MyIcon name={'common/detail'} w={4} />}
|
||||
fontSize={'12px'}
|
||||
fontWeight={'medium'}
|
||||
mr={2}
|
||||
onClick={() => setEvalDetailId(item._id)}
|
||||
>
|
||||
{t('dashboard_evaluation:detail')}
|
||||
</Button>
|
||||
|
||||
<PopoverConfirm
|
||||
type="delete"
|
||||
Trigger={
|
||||
<IconButton
|
||||
aria-label="delete"
|
||||
size={'mdSquare'}
|
||||
variant={'whiteDanger'}
|
||||
icon={<MyIcon name={'delete'} w={4} />}
|
||||
/>
|
||||
}
|
||||
content={t('dashboard_evaluation:comfirm_delete_task')}
|
||||
onConfirm={() => onDeleteEval({ evalId: item._id })}
|
||||
/>
|
||||
</Td>
|
||||
</Tr>
|
||||
);
|
||||
})}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
{total >= pageSize && (
|
||||
<Flex mt={4} justifyContent="center">
|
||||
<Pagination />
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
)}
|
||||
</DashboardContainer>
|
||||
|
||||
@@ -79,6 +79,7 @@ import type {
|
||||
GetApiDatasetPathBody,
|
||||
GetApiDatasetPathResponse
|
||||
} from '@/pages/api/core/dataset/apiDataset/getPathNames';
|
||||
import type { DelCollectionBody } from '@/pages/api/core/dataset/collection/delete';
|
||||
|
||||
/* ======================== dataset ======================= */
|
||||
export const getDatasets = (data: GetDatasetListBody) =>
|
||||
@@ -216,8 +217,8 @@ export const postCreateDatasetApiDatasetCollection = (
|
||||
|
||||
export const putDatasetCollectionById = (data: UpdateDatasetCollectionParams) =>
|
||||
POST(`/core/dataset/collection/update`, data);
|
||||
export const delDatasetCollectionById = (params: { id: string }) =>
|
||||
DELETE(`/core/dataset/collection/delete`, params);
|
||||
export const delDatasetCollectionById = (params: DelCollectionBody) =>
|
||||
POST(`/core/dataset/collection/delete`, params);
|
||||
export const postLinkCollectionSync = (collectionId: string) =>
|
||||
POST<DatasetCollectionSyncResultEnum>(`/core/dataset/collection/sync`, {
|
||||
collectionId
|
||||
|
||||
Reference in New Issue
Block a user