From ce36230285edae8fed6d36f06a6e9f8c8aeb2141 Mon Sep 17 00:00:00 2001 From: Archer <545436317@qq.com> Date: Fri, 15 Aug 2025 17:56:49 +0800 Subject: [PATCH] perf: page ui (#5469) * perf: page ui * fix: icon * limit chat items * limit chat items --- .../web/common/hook/tableMultiple/index.md | 15 ++ document/content/docs/upgrading/4-12/4121.mdx | 2 +- document/data/doc-last-modified.json | 2 +- .../web/components/common/Icon/constants.ts | 2 + .../common/Icon/icons/common/first_page.svg | 3 + .../common/Icon/icons/common/latest_page.svg | 3 + .../Icon/icons/common/leftArrowLight.svg | 5 +- .../Icon/icons/common/rightArrowLight.svg | 7 +- packages/web/hooks/usePagination.tsx | 193 ++++++++++++------ packages/web/hooks/useTableMultipleSelect.tsx | 98 +++++++++ packages/web/i18n/en/common.json | 3 + packages/web/i18n/en/dataset.json | 2 + packages/web/i18n/zh-CN/common.json | 5 +- packages/web/i18n/zh-CN/dataset.json | 2 + packages/web/i18n/zh-Hant/common.json | 3 + packages/web/i18n/zh-Hant/dataset.json | 2 + packages/web/styles/theme.ts | 24 ++- .../pageComponents/account/bill/BillTable.tsx | 19 +- .../account/bill/InvoiceTable.tsx | 19 +- .../account/usage/UsageTable.tsx | 94 ++++----- .../app/detail/Logs/LogChart.tsx | 7 +- .../app/detail/Logs/LogTable.tsx | 20 +- .../app/detail/Plugin/Header.tsx | 13 +- .../app/detail/Workflow/Header.tsx | 13 +- .../app/evaluation/DetailModal.tsx | 12 +- .../dataset/detail/CollectionCard/Context.tsx | 2 +- .../dataset/detail/CollectionCard/index.tsx | 115 ++++++++--- projects/app/src/pages/account/bill/index.tsx | 7 +- projects/app/src/pages/account/inform.tsx | 4 +- projects/app/src/pages/account/promotion.tsx | 4 +- projects/app/src/pages/api/admin/initv4121.ts | 7 +- .../api/core/dataset/collection/delete.ts | 53 +++-- .../pages/api/core/dataset/collection/list.ts | 2 +- .../api/core/dataset/collection/listV2.ts | 2 +- .../src/pages/dashboard/evaluation/index.tsx | 172 ++++++++-------- projects/app/src/web/core/dataset/api.ts | 5 +- 36 files changed, 619 insertions(+), 322 deletions(-) create mode 100644 .claude/design/web/common/hook/tableMultiple/index.md create mode 100644 packages/web/components/common/Icon/icons/common/first_page.svg create mode 100644 packages/web/components/common/Icon/icons/common/latest_page.svg create mode 100644 packages/web/hooks/useTableMultipleSelect.tsx diff --git a/.claude/design/web/common/hook/tableMultiple/index.md b/.claude/design/web/common/hook/tableMultiple/index.md new file mode 100644 index 000000000..e1a557353 --- /dev/null +++ b/.claude/design/web/common/hook/tableMultiple/index.md @@ -0,0 +1,15 @@ +# 背景 + +一个通用表格多选 hook/component, 它可以实现表格每一行数据的选择,并且在触发一次选择后,会有特殊的按键进行批量操作。 + +# 具体描述 + +当有一行被选中时,底部会出现悬浮层,可以进行批量操作(具体有哪些批量操作由外部决定) + +![alt text](./image-1.png) + +# 预期封装 + +1. 选中的值存储在 hook 里,便于判断是否触发底部悬浮层 +2. 悬浮层外层 Box 在 hook 里,child 由调用组件实现 +3. FastGPT/packages/web/hooks/useTableMultipleSelect.tsx 在这个文件下实现 \ No newline at end of file diff --git a/document/content/docs/upgrading/4-12/4121.mdx b/document/content/docs/upgrading/4-12/4121.mdx index 4c91818be..68a957f86 100644 --- a/document/content/docs/upgrading/4-12/4121.mdx +++ b/document/content/docs/upgrading/4-12/4121.mdx @@ -3,7 +3,6 @@ title: 'V4.12.1(进行中)' description: 'FastGPT V4.12.1 更新说明' --- - ## 🚀 新增内容 1. Prompt 自动生成和优化。 @@ -14,6 +13,7 @@ description: 'FastGPT V4.12.1 更新说明' 1. 工作流响应优化,主动指定响应值进入历史记录,而不是根据 key 决定。 2. 避免工作流中,变量替换导致的死循环或深度递归风险。 3. 对话日志导出,固定导出对话详情。 +4. 分页器 UI 优化。 ## 🐛 修复 diff --git a/document/data/doc-last-modified.json b/document/data/doc-last-modified.json index 5d895f6f2..56b87e232 100644 --- a/document/data/doc-last-modified.json +++ b/document/data/doc-last-modified.json @@ -103,7 +103,7 @@ "document/content/docs/upgrading/4-11/4110.mdx": "2025-08-05T23:20:39+08:00", "document/content/docs/upgrading/4-11/4111.mdx": "2025-08-07T22:49:09+08:00", "document/content/docs/upgrading/4-12/4120.mdx": "2025-08-12T22:45:19+08:00", - "document/content/docs/upgrading/4-12/4121.mdx": "2025-08-15T14:27:32+08:00", + "document/content/docs/upgrading/4-12/4121.mdx": "2025-08-15T17:10:04+08:00", "document/content/docs/upgrading/4-8/40.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/41.mdx": "2025-08-02T19:38:37+08:00", "document/content/docs/upgrading/4-8/42.mdx": "2025-08-02T19:38:37+08:00", diff --git a/packages/web/components/common/Icon/constants.ts b/packages/web/components/common/Icon/constants.ts index dae776d59..76eafedde 100644 --- a/packages/web/components/common/Icon/constants.ts +++ b/packages/web/components/common/Icon/constants.ts @@ -52,6 +52,7 @@ export const iconPaths = { 'common/errorFill': () => import('./icons/common/errorFill.svg'), 'common/file/move': () => import('./icons/common/file/move.svg'), 'common/fileNotFound': () => import('./icons/common/fileNotFound.svg'), + 'common/first_page': () => import('./icons/common/first_page.svg'), 'common/folderFill': () => import('./icons/common/folderFill.svg'), 'common/folderImport': () => import('./icons/common/folderImport.svg'), 'common/fullScreenLight': () => import('./icons/common/fullScreenLight.svg'), @@ -67,6 +68,7 @@ export const iconPaths = { 'common/language/China': () => import('./icons/common/language/China.svg'), 'common/language/en': () => import('./icons/common/language/en.svg'), 'common/language/zh': () => import('./icons/common/language/zh.svg'), + 'common/latest_page': () => import('./icons/common/latest_page.svg'), 'common/layer': () => import('./icons/common/layer.svg'), 'common/leftArrowLight': () => import('./icons/common/leftArrowLight.svg'), 'common/line': () => import('./icons/common/line.svg'), diff --git a/packages/web/components/common/Icon/icons/common/first_page.svg b/packages/web/components/common/Icon/icons/common/first_page.svg new file mode 100644 index 000000000..ca86c07ee --- /dev/null +++ b/packages/web/components/common/Icon/icons/common/first_page.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/common/latest_page.svg b/packages/web/components/common/Icon/icons/common/latest_page.svg new file mode 100644 index 000000000..30bbac7b8 --- /dev/null +++ b/packages/web/components/common/Icon/icons/common/latest_page.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/common/leftArrowLight.svg b/packages/web/components/common/Icon/icons/common/leftArrowLight.svg index 376eb1258..f41082aed 100644 --- a/packages/web/components/common/Icon/icons/common/leftArrowLight.svg +++ b/packages/web/components/common/Icon/icons/common/leftArrowLight.svg @@ -1,4 +1,3 @@ - - + + \ No newline at end of file diff --git a/packages/web/components/common/Icon/icons/common/rightArrowLight.svg b/packages/web/components/common/Icon/icons/common/rightArrowLight.svg index 8a22d0221..0c6b08a5b 100644 --- a/packages/web/components/common/Icon/icons/common/rightArrowLight.svg +++ b/packages/web/components/common/Icon/icons/common/rightArrowLight.svg @@ -1,6 +1,3 @@ - - + + \ No newline at end of file diff --git a/packages/web/hooks/usePagination.tsx b/packages/web/hooks/usePagination.tsx index 7571aec93..cc0d9f4f1 100644 --- a/packages/web/hooks/usePagination.tsx +++ b/packages/web/hooks/usePagination.tsx @@ -1,12 +1,22 @@ -import { useRef, useState, useCallback, type RefObject, type ReactNode, useMemo } from 'react'; -import { IconButton, Flex, Box, Input, type BoxProps } from '@chakra-ui/react'; -import { ArrowBackIcon, ArrowForwardIcon } from '@chakra-ui/icons'; +import { + useRef, + useState, + useCallback, + type RefObject, + type ReactNode, + useMemo, + useEffect +} from 'react'; +import type { FlexProps } from '@chakra-ui/react'; +import { Flex, Box, type BoxProps } from '@chakra-ui/react'; +import MyIcon from '../components/common/Icon'; +import type { IconNameType } from '../components/common/Icon/type'; import { useTranslation } from 'next-i18next'; import { useToast } from './useToast'; import { getErrText } from '@fastgpt/global/common/error/utils'; import { useBoolean, - useLockFn, + useCreation, useMemoizedFn, useRequest, useScroll, @@ -14,13 +24,16 @@ import { } from 'ahooks'; import { type PaginationProps, type PaginationResponse } from '../common/fetch/type'; +import MyMenu from '../components/common/MyMenu'; +import { useSystem } from './useSystem'; const thresholdVal = 200; export function usePagination( api: (data: PaginationProps) => Promise>, { - pageSize = 10, + defaultPageSize = 10, + pageSizeOptions: defaultPageSizeOptions, params, defaultRequest = true, type = 'button', @@ -31,7 +44,8 @@ export function usePagination( pollingInterval, pollingWhenHidden = false }: { - pageSize?: number; + defaultPageSize?: number; + pageSizeOptions?: number[]; params?: DataT; defaultRequest?: boolean; type?: 'button' | 'scroll'; @@ -45,11 +59,18 @@ export function usePagination( } ) { const { toast } = useToast(); + const { isPc } = useSystem(); const { t } = useTranslation(); const [isLoading, { setTrue, setFalse }] = useBoolean(false); const [pageNum, setPageNum] = useState(1); + const [pageSize, setPageSize] = useState(defaultPageSize); + const pageSizeOptions = useCreation( + () => defaultPageSizeOptions || [10, 20, 50, 100], + [defaultPageSizeOptions] + ); + const [total, setTotal] = useState(0); const [data, setData] = useState([]); const totalDataLength = useMemo(() => Math.max(total, data.length), [total, data.length]); @@ -119,67 +140,110 @@ export function usePagination( const Pagination = useCallback(() => { const maxPage = Math.ceil(totalDataLength / pageSize); - return ( - - } - aria-label={'left'} - size={'smSquare'} - isLoading={isLoading} - onClick={() => fetchData(pageNum - 1)} - /> - - @@ -147,11 +148,6 @@ const BillTable = () => { ))}
- {total >= 20 && ( - - - - )} {!isLoading && bills.length === 0 && ( { )} + {total >= pageSize && ( + + + + )} {!!billDetail && ( setBillDetail(undefined)} /> )} diff --git a/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx b/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx index 27f1aa509..9c9d9a690 100644 --- a/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx +++ b/projects/app/src/pageComponents/account/bill/InvoiceTable.tsx @@ -32,14 +32,15 @@ const InvoiceTable = () => { data: invoices, isLoading, Pagination, - total + total, + pageSize } = usePagination(getInvoiceRecords, { - pageSize: 20 + defaultPageSize: 10 }); return ( - - + + @@ -101,11 +102,6 @@ const InvoiceTable = () => { ))}
- {total >= 20 && ( - - - - )} {!isLoading && invoices.length === 0 && ( { )}
+ {total >= pageSize && ( + + + + )} {!!invoiceDetailData && ( setInvoiceDetailData('')} /> )} diff --git a/projects/app/src/pageComponents/account/usage/UsageTable.tsx b/projects/app/src/pageComponents/account/usage/UsageTable.tsx index 355a01a5d..45dc90407 100644 --- a/projects/app/src/pageComponents/account/usage/UsageTable.tsx +++ b/projects/app/src/pageComponents/account/usage/UsageTable.tsx @@ -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 ( - <> + {Tabs} {Selectors} @@ -123,54 +123,46 @@ const UsageTableList = ({ onConfirm={exportUsage} /> - - - - - - - - - - - - - - - - {usages.map((item) => ( - - - - - - - - - ))} - -
{t('common:user.Time')}{t('account_usage:member')}{t('account_usage:user_type')}{t('account_usage:project_name')}{t('account_usage:total_points')}
{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')} - - - {item.sourceMember.name} - - {t(UsageSourceMap[item.source]?.label as any) || '-'} - {t(item.appName as any) || '-'} - {formatNumber(item.totalPoints) || 0} - -
- {!isLoading && usages.length === 0 && ( - - )} -
-
-
+ + + + + + + + + + + + + + {usages.map((item) => ( + + + + + + + + + ))} + +
{t('common:user.Time')}{t('account_usage:member')}{t('account_usage:user_type')}{t('account_usage:project_name')}{t('account_usage:total_points')}
{dayjs(item.time).format('YYYY/MM/DD HH:mm:ss')} + + + {item.sourceMember.name} + + {t(UsageSourceMap[item.source]?.label as any) || '-'} + {t(item.appName as any) || '-'} + {formatNumber(item.totalPoints) || 0} + +
+ {!isLoading && usages.length === 0 && ( + + )} +
@@ -178,7 +170,7 @@ const UsageTableList = ({ {!!usageDetail && ( setUsageDetail(undefined)} /> )} - +
); }; diff --git a/projects/app/src/pageComponents/app/detail/Logs/LogChart.tsx b/projects/app/src/pageComponents/app/detail/Logs/LogChart.tsx index cb38a902b..a979d2fd7 100644 --- a/projects/app/src/pageComponents/app/detail/Logs/LogChart.tsx +++ b/projects/app/src/pageComponents/app/detail/Logs/LogChart.tsx @@ -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(offsetOptions[0].value); - const { data: chartData } = useRequest2( + const { data: chartData, loading } = useRequest2( async () => { return getAppChartData({ appId, @@ -331,7 +332,7 @@ const LogChart = ({ ]); return ( - + -
+ ); }; diff --git a/projects/app/src/pageComponents/app/detail/Logs/LogTable.tsx b/projects/app/src/pageComponents/app/detail/Logs/LogTable.tsx index 647fbdeae..e81f07a9c 100644 --- a/projects/app/src/pageComponents/app/detail/Logs/LogTable.tsx +++ b/projects/app/src/pageComponents/app/detail/Logs/LogTable.tsx @@ -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 ( - + {showSourceSelector && ( @@ -465,7 +467,7 @@ const LogTable = ({ /> - + @@ -496,9 +498,11 @@ const LogTable = ({ {logs.length === 0 && !isLoading && } - - - + {total >= pageSize && ( + + + + )} {!!detailLogsId && ( )} - + ); }; diff --git a/projects/app/src/pageComponents/app/detail/Plugin/Header.tsx b/projects/app/src/pageComponents/app/detail/Plugin/Header.tsx index 1df64a484..51651fb07 100644 --- a/projects/app/src/pageComponents/app/detail/Plugin/Header.tsx +++ b/projects/app/src/pageComponents/app/detail/Plugin/Header.tsx @@ -149,11 +149,12 @@ const Header = () => { p={0.5} borderRadius={'sm'} > - } + aria-label={''} + size={'xs'} + w={'1rem'} + variant={'ghost'} /> @@ -213,8 +214,6 @@ const Header = () => { isPc, currentTab, isSaved, - onBack, - onOpenBackConfirm, isV2Workflow, t, showHistoryModal, diff --git a/projects/app/src/pageComponents/app/detail/Workflow/Header.tsx b/projects/app/src/pageComponents/app/detail/Workflow/Header.tsx index 1df64a484..51651fb07 100644 --- a/projects/app/src/pageComponents/app/detail/Workflow/Header.tsx +++ b/projects/app/src/pageComponents/app/detail/Workflow/Header.tsx @@ -149,11 +149,12 @@ const Header = () => { p={0.5} borderRadius={'sm'} > - } + aria-label={''} + size={'xs'} + w={'1rem'} + variant={'ghost'} /> @@ -213,8 +214,6 @@ const Header = () => { isPc, currentTab, isSaved, - onBack, - onOpenBackConfirm, isV2Workflow, t, showHistoryModal, diff --git a/projects/app/src/pageComponents/app/evaluation/DetailModal.tsx b/projects/app/src/pageComponents/app/evaluation/DetailModal.tsx index a2bbf8b52..ccb91da7e 100644 --- a/projects/app/src/pageComponents/app/evaluation/DetailModal.tsx +++ b/projects/app/src/pageComponents/app/evaluation/DetailModal.tsx @@ -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 = ({ })} - - - + {total >= pageSize && ( + + + + )} {evalItem ? ( diff --git a/projects/app/src/pageComponents/dataset/detail/CollectionCard/Context.tsx b/projects/app/src/pageComponents/dataset/detail/CollectionCard/Context.tsx index 1813196dd..1e8d95ac3 100644 --- a/projects/app/src/pageComponents/dataset/detail/CollectionCard/Context.tsx +++ b/projects/app/src/pageComponents/dataset/detail/CollectionCard/Context.tsx @@ -128,7 +128,7 @@ const CollectionPageContextProvider = ({ children }: { children: ReactNode }) => pageNum, pageSize } = usePagination(getDatasetCollections, { - pageSize: 20, + defaultPageSize: 20, params: { datasetId, parentId, diff --git a/projects/app/src/pageComponents/dataset/detail/CollectionCard/index.tsx b/projects/app/src/pageComponents/dataset/detail/CollectionCard/index.tsx index c277ae8f9..8e15abb7d 100644 --- a/projects/app/src/pageComponents/dataset/detail/CollectionCard/index.tsx +++ b/projects/app/src/pageComponents/dataset/detail/CollectionCard/index.tsx @@ -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 ( - + {/* header */}
{/* collection table */} - +
- + @@ -241,17 +260,27 @@ const CollectionCard = () => { }} >
{t('common:Name')} + + + {t('common:Name')} + + {t('dataset:collection.training_type')} {t('dataset:collection_data_count')} {t('dataset:collection.Create update time')} - - - - - {collection.name} - - - - {feConfigs?.isPlus && !!collection.tags?.length && ( - - )} + + e.stopPropagation()}> + toggleSelect(collection)} + /> + + + + + + + {collection.name} + + + + {feConfigs?.isPlus && !!collection.tags?.length && ( + + )} + + {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 = () => { ))}
+ + {total === 0 && } +
+ + + + + } + > {total > pageSize && ( - + )} - {total === 0 && } -
+ diff --git a/projects/app/src/pages/account/bill/index.tsx b/projects/app/src/pages/account/bill/index.tsx index d2daff59d..a1cf7afd1 100644 --- a/projects/app/src/pages/account/bill/index.tsx +++ b/projects/app/src/pages/account/bill/index.tsx @@ -27,9 +27,10 @@ const BillAndInvoice = () => { return ( - + { )} - + {invoiceTab === InvoiceTabEnum.bill && } {invoiceTab === InvoiceTabEnum.invoice && } {invoiceTab === InvoiceTabEnum.invoiceHeader && } @@ -73,7 +74,7 @@ const BillAndInvoice = () => { }} /> )} - + ); }; diff --git a/projects/app/src/pages/account/inform.tsx b/projects/app/src/pages/account/inform.tsx index 5127db9cc..1d28a25cd 100644 --- a/projects/app/src/pages/account/inform.tsx +++ b/projects/app/src/pages/account/inform.tsx @@ -44,7 +44,7 @@ const InformTable = () => { getData, pageNum } = usePagination(getInforms, { - pageSize: 20 + defaultPageSize: 20 }); return ( @@ -147,7 +147,7 @@ const InformTable = () => { )} {total > pageSize && ( - + )} diff --git a/projects/app/src/pages/account/promotion.tsx b/projects/app/src/pages/account/promotion.tsx index b1d76cbbf..0a807e3dc 100644 --- a/projects/app/src/pages/account/promotion.tsx +++ b/projects/app/src/pages/account/promotion.tsx @@ -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 = () => { )} {total > pageSize && ( - + )} diff --git a/projects/app/src/pages/api/admin/initv4121.ts b/projects/app/src/pages/api/admin/initv4121.ts index 16bfc8911..81c61e30b 100644 --- a/projects/app/src/pages/api/admin/initv4121.ts +++ b/projects/app/src/pages/api/admin/initv4121.ts @@ -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() !== '') { diff --git a/projects/app/src/pages/api/core/dataset/collection/delete.ts b/projects/app/src/pages/api/core/dataset/collection/delete.ts index 14187554b..003ca6f44 100644 --- a/projects/app/src/pages/api/core/dataset/collection/delete.ts +++ b/projects/app/src/pages/api/core/dataset/collection/delete.ts @@ -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) { + 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 diff --git a/projects/app/src/pages/api/core/dataset/collection/list.ts b/projects/app/src/pages/api/core/dataset/collection/list.ts index 7a40eb46a..55efcdc7d 100644 --- a/projects/app/src/pages/api/core/dataset/collection/list.ts +++ b/projects/app/src/pages/api/core/dataset/collection/list.ts @@ -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({ diff --git a/projects/app/src/pages/api/core/dataset/collection/listV2.ts b/projects/app/src/pages/api/core/dataset/collection/listV2.ts index bf237ac73..f510b18ea 100644 --- a/projects/app/src/pages/api/core/dataset/collection/listV2.ts +++ b/projects/app/src/pages/api/core/dataset/collection/listV2.ts @@ -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 diff --git a/projects/app/src/pages/dashboard/evaluation/index.tsx b/projects/app/src/pages/dashboard/evaluation/index.tsx index a318d4cb4..5cbc16b1e 100644 --- a/projects/app/src/pages/dashboard/evaluation/index.tsx +++ b/projects/app/src/pages/dashboard/evaluation/index.tsx @@ -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 = () => { {renderHeader(MenuIcon)} - - - - - - - - - - - - - - - - - {evaluationList.map((item) => { - return ( - - - - - - - - + + + + + + ); + })} + +
{t('dashboard_evaluation:Task_name')}{t('dashboard_evaluation:Progress')}{t('dashboard_evaluation:Executor')}{t('dashboard_evaluation:Evaluation_app')}{t('dashboard_evaluation:Start_end_time')}{t('dashboard_evaluation:Overall_score')}{t('dashboard_evaluation:Action')}
- {item.name} - {renderProgress(item)} - - - {item.executorName} - - - - - {item.appName} - - - {formatTime2YMDHM(item.createTime)} - {formatTime2YMDHM(item.finishTime)} - - {typeof item.score === 'number' ? (item.score * 100).toFixed(2) : '-'} - - - - } - /> - } - content={t('dashboard_evaluation:comfirm_delete_task')} - onConfirm={() => onDeleteEval({ evalId: item._id })} + + + + + + + + + + + + + + + + {evaluationList.map((item) => { + return ( + + + + - - ); - })} - -
{t('dashboard_evaluation:Task_name')}{t('dashboard_evaluation:Progress')}{t('dashboard_evaluation:Executor')}{t('dashboard_evaluation:Evaluation_app')}{t('dashboard_evaluation:Start_end_time')}{t('dashboard_evaluation:Overall_score')}{t('dashboard_evaluation:Action')}
+ {item.name} + {renderProgress(item)} + + -
-
- - - - + {item.executorName} + +
+ + + {item.appName} + + + {formatTime2YMDHM(item.createTime)} + {formatTime2YMDHM(item.finishTime)} + + {typeof item.score === 'number' ? (item.score * 100).toFixed(2) : '-'} + + + + } + /> + } + content={t('dashboard_evaluation:comfirm_delete_task')} + onConfirm={() => onDeleteEval({ evalId: item._id })} + /> +
+
+ {total >= pageSize && ( + + + + )}
)} diff --git a/projects/app/src/web/core/dataset/api.ts b/projects/app/src/web/core/dataset/api.ts index 64f0d0b47..d0c273089 100644 --- a/projects/app/src/web/core/dataset/api.ts +++ b/projects/app/src/web/core/dataset/api.ts @@ -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(`/core/dataset/collection/sync`, { collectionId