From 62bcff2ff06496ebd0ed34958483683022661dc9 Mon Sep 17 00:00:00 2001 From: archer <545436317@qq.com> Date: Mon, 13 Jan 2025 13:40:42 +0800 Subject: [PATCH] perf: scroll page code --- .../support/user/team/teamMemberSchema.ts | 8 +- .../web/components/common/MySelect/index.tsx | 80 +++++----- .../web/components/common/UserBox/index.tsx | 2 +- packages/web/hooks/useScrollPagination.tsx | 6 +- packages/web/i18n/en/common.json | 3 +- packages/web/i18n/zh-CN/account_team.json | 1 - packages/web/i18n/zh-CN/common.json | 3 +- packages/web/i18n/zh-Hant/common.json | 3 +- .../account/team/components/MemberTable.tsx | 148 +++++++++--------- .../team/components/OrgManage/index.tsx | 66 ++++---- .../pages/account/team/components/context.tsx | 4 +- projects/app/src/pages/account/team/index.tsx | 127 ++++++++------- projects/app/src/pages/api/admin/initv4819.ts | 38 +++-- .../components/PublishHistoriesSlider.tsx | 63 +++++--- 14 files changed, 302 insertions(+), 250 deletions(-) diff --git a/packages/service/support/user/team/teamMemberSchema.ts b/packages/service/support/user/team/teamMemberSchema.ts index e3d729e19..f7893c0d0 100644 --- a/packages/service/support/user/team/teamMemberSchema.ts +++ b/packages/service/support/user/team/teamMemberSchema.ts @@ -20,6 +20,10 @@ const TeamMemberSchema = new Schema({ ref: userCollectionName, required: true }, + avatar: { + type: String, + default: () => getRandomUserAvatar() + }, name: { type: String, default: 'Member' @@ -36,10 +40,6 @@ const TeamMemberSchema = new Schema({ type: Boolean, default: false }, - avatar: { - type: String, - default: getRandomUserAvatar() - }, // Abandoned role: { diff --git a/packages/web/components/common/MySelect/index.tsx b/packages/web/components/common/MySelect/index.tsx index d9401b38c..ddc81bbaf 100644 --- a/packages/web/components/common/MySelect/index.tsx +++ b/packages/web/components/common/MySelect/index.tsx @@ -97,6 +97,46 @@ const MySelect = ( const isSelecting = loading || isLoading; + const ListRender = useMemo(() => { + return ( + <> + {list.map((item, i) => ( + + { + if (onChange && value !== item.value) { + onChange(item.value); + } + }} + whiteSpace={'pre-wrap'} + fontSize={'sm'} + display={'block'} + > + {item.label} + {item.description && ( + + {item.description} + + )} + + {item.showBorder && } + + ))} + + ); + }, []); + return ( ( maxH={'40vh'} overflowY={'auto'} > - {(() => { - const component = list.map((item, i) => ( - - { - if (onChange && value !== item.value) { - onChange(item.value); - } - }} - whiteSpace={'pre-wrap'} - fontSize={'sm'} - display={'block'} - > - {item.label} - {item.description && ( - - {item.description} - - )} - - {item.showBorder && } - - )); - if (ScrollData) { - return {component}; - } - return component; - })()} + {ScrollData ? {ListRender} : ListRender} diff --git a/packages/web/components/common/UserBox/index.tsx b/packages/web/components/common/UserBox/index.tsx index b57e96ea3..8e659fa1a 100644 --- a/packages/web/components/common/UserBox/index.tsx +++ b/packages/web/components/common/UserBox/index.tsx @@ -15,7 +15,7 @@ function UserBox({ sourceMember, avatarSize = '1.25rem', ...props }: UserBoxProp {sourceMember.name} - {sourceMember.status === 'leave' && {t('account_team:leaved')}} + {sourceMember.status === 'leave' && {t('common:user_leaved')}} ); } diff --git a/packages/web/hooks/useScrollPagination.tsx b/packages/web/hooks/useScrollPagination.tsx index 83a5ad11b..f16702007 100644 --- a/packages/web/hooks/useScrollPagination.tsx +++ b/packages/web/hooks/useScrollPagination.tsx @@ -269,8 +269,10 @@ export function useScrollPagination< ({ children, ScrollContainerRef, + isLoading, ...props }: { + isLoading?: boolean; children: ReactNode; ScrollContainerRef?: RefObject; } & BoxProps) => { @@ -302,7 +304,7 @@ export function useScrollPagination< ); return ( - + {scrollLoadType === 'top' && total > 0 && isLoading && ( {t('common:common.is_requesting')} @@ -325,7 +327,7 @@ export function useScrollPagination< )} {isEmpty && EmptyTip} - + ); } ); diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json index 1feb36b2a..9871c5528 100644 --- a/packages/web/i18n/en/common.json +++ b/packages/web/i18n/en/common.json @@ -39,6 +39,7 @@ "classification": "Classification", "click_to_resume": "Click to Resume", "code_editor": "Code Editor", + "code_error.account_error": "Incorrect account name or password", "code_error.app_error.invalid_app_type": "Invalid Application Type", "code_error.app_error.invalid_owner": "Unauthorized Application Owner", "code_error.app_error.not_exist": "Application Does Not Exist", @@ -95,7 +96,6 @@ "code_error.team_error.website_sync_not_enough": "Unauthorized to Use Website Sync", "code_error.token_error_code.403": "Invalid Login Status, Please Re-login", "code_error.user_error.balance_not_enough": "Insufficient Account Balance", - "code_error.account_error": "Incorrect account name or password", "code_error.user_error.bin_visitor_guest": "You Are Currently a Guest, Unauthorized to Operate", "code_error.user_error.un_auth_user": "User Not Found", "common.Action": "Action", @@ -1273,6 +1273,7 @@ "user.team.role.Visitor": "visitor", "user.team.role.writer": "writable member", "user.type": "Type", + "user_leaved": "Leaved", "verification": "Verification", "workflow.template.communication": "Communication", "xx_search_result": "{{key}} Search Results", diff --git a/packages/web/i18n/zh-CN/account_team.json b/packages/web/i18n/zh-CN/account_team.json index fcaad74c4..91587efc2 100644 --- a/packages/web/i18n/zh-CN/account_team.json +++ b/packages/web/i18n/zh-CN/account_team.json @@ -35,7 +35,6 @@ "user_team_invite_member": "邀请成员", "user_team_leave_team": "离开团队", "user_team_leave_team_failed": "离开团队失败", - "leaved": "已离职", "waiting": "待接受", "sync_immediately": "立即同步", "sync_member_failed": "同步成员失败", diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json index bbbfcb4ed..fa46e013b 100644 --- a/packages/web/i18n/zh-CN/common.json +++ b/packages/web/i18n/zh-CN/common.json @@ -43,6 +43,7 @@ "classification": "分类", "click_to_resume": "点击恢复", "code_editor": "代码编辑", + "code_error.account_error": "账号名或密码错误", "code_error.app_error.invalid_app_type": "错误的应用类型", "code_error.app_error.invalid_owner": "非法的应用所有者", "code_error.app_error.not_exist": "应用不存在", @@ -99,7 +100,6 @@ "code_error.team_error.website_sync_not_enough": "无权使用Web站点同步~", "code_error.token_error_code.403": "登录状态无效,请重新登录", "code_error.user_error.balance_not_enough": "账号余额不足~", - "code_error.account_error": "账号名或密码错误", "code_error.user_error.bin_visitor_guest": "您当前身份为游客,无权操作", "code_error.user_error.un_auth_user": "找不到该用户", "common.Action": "操作", @@ -1268,6 +1268,7 @@ "user.team.role.Visitor": "访客", "user.team.role.writer": "可写成员", "user.type": "类型", + "user_leaved": "已离开", "verification": "验证", "workflow.template.communication": "通信", "xx_search_result": "{{key}} 的搜索结果", diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json index 2d3cfc13a..efa9bbf46 100644 --- a/packages/web/i18n/zh-Hant/common.json +++ b/packages/web/i18n/zh-Hant/common.json @@ -39,6 +39,7 @@ "classification": "分類", "click_to_resume": "點選繼續", "code_editor": "程式碼編輯器", + "code_error.account_error": "帳號名稱或密碼錯誤", "code_error.app_error.invalid_app_type": "無效的應用程式類型", "code_error.app_error.invalid_owner": "非法的應用程式擁有者", "code_error.app_error.not_exist": "應用程式不存在", @@ -95,7 +96,6 @@ "code_error.team_error.website_sync_not_enough": "無權使用網站同步", "code_error.token_error_code.403": "登入狀態無效,請重新登入", "code_error.user_error.balance_not_enough": "帳戶餘額不足", - "code_error.account_error": "帳號名稱或密碼錯誤", "code_error.user_error.bin_visitor_guest": "您目前身份為訪客,無權操作", "code_error.user_error.un_auth_user": "找不到此使用者", "common.Action": "操作", @@ -1273,6 +1273,7 @@ "user.team.role.Visitor": "訪客", "user.team.role.writer": "可寫入成員", "user.type": "類型", + "user_leaved": "已離開", "verification": "驗證", "workflow.template.communication": "通訊", "xx_search_result": "{{key}} 的搜尋結果", diff --git a/projects/app/src/pages/account/team/components/MemberTable.tsx b/projects/app/src/pages/account/team/components/MemberTable.tsx index da2aa1532..05eabd09b 100644 --- a/projects/app/src/pages/account/team/components/MemberTable.tsx +++ b/projects/app/src/pages/account/team/components/MemberTable.tsx @@ -31,6 +31,7 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { delLeaveTeam } from '@/web/support/user/team/api'; import { postSyncMembers } from '@/web/support/user/api'; import MyLoading from '@fastgpt/web/components/common/MyLoading'; +import { TeamMemberRoleEnum } from '@fastgpt/global/support/user/team/constant'; const InviteModal = dynamic(() => import('./InviteModal')); const TeamTagModal = dynamic(() => import('@/components/support/user/team/TeamTagModal')); @@ -169,84 +170,83 @@ function MemberTable({ Tabs }: { Tabs: React.ReactNode }) { - {MemberScrollData && ( - - - - -
- {t('account_team:user_name')} + + + + + + + {!isSyncMember && ( + - + )} + + + + {members?.map((item) => ( + + + {!isSyncMember && ( - + )} - - - {members?.map((item) => ( - - - - {!isSyncMember && ( - - )} - - ))} - -
+ {t('account_team:user_name')} + {t('account_team:member_group')} + {t('common:common.Action')} {t('account_team:member_group')}
+ + + + {item.memberName} + {item.status === 'waiting' && ( + + {t('account_team:waiting')} + + )} + + + + + group.members.map((m) => m.tmbId).includes(item.tmbId) + ) + .map((g) => g.name)} + max={3} + /> + - {t('common:common.Action')} - + {userInfo?.team.permission.hasManagePer && + item.role !== TeamMemberRoleEnum.owner && + item.tmbId !== userInfo?.team.tmbId && ( + { + openRemoveMember( + () => + delRemoveMember(item.tmbId).then(() => + Promise.all([refetchGroups(), refetchMembers()]) + ), + undefined, + t('account_team:remove_tip', { + username: item.memberName + }) + )(); + }} + /> + )} +
- - - - {item.memberName} - {item.status === 'waiting' && ( - - {t('account_team:waiting')} - - )} - - - - - group.members.map((m) => m.tmbId).includes(item.tmbId) - ) - .map((g) => g.name)} - max={3} - /> - - userInfo?.team.permission.hasManagePer && item.role !== - TeamMemberRoleEnum.owner && item.tmbId !== userInfo?.team.tmbId && ( - { - openRemoveMember( - () => - delRemoveMember(item.tmbId).then(() => - Promise.all([refetchGroups(), refetchMembers()]) - ), - undefined, - t('account_team:remove_tip', { - username: item.memberName - }) - )(); - }} - /> - ) -
-
- )} + ))} + +
+
diff --git a/projects/app/src/pages/account/team/components/OrgManage/index.tsx b/projects/app/src/pages/account/team/components/OrgManage/index.tsx index 8ecc18f2f..8d2248657 100644 --- a/projects/app/src/pages/account/team/components/OrgManage/index.tsx +++ b/projects/app/src/pages/account/team/components/OrgManage/index.tsx @@ -163,14 +163,20 @@ function OrgTable({ Tabs }: { Tabs: React.ReactNode }) { {Tabs} - + - + {/* Table */} - - + +
@@ -326,33 +332,33 @@ function OrgTable({ Tabs }: { Tabs: React.ReactNode }) { )} - - {!!editOrg && ( - setEditOrg(undefined)} - onSuccess={refetchOrgs} - /> - )} - {!!movingOrg && ( - setMovingOrg(undefined)} - onSuccess={refetchOrgs} - /> - )} - {!!manageMemberOrg && ( - setManageMemberOrg(undefined)} - /> - )} - - - + + {!!editOrg && ( + setEditOrg(undefined)} + onSuccess={refetchOrgs} + /> + )} + {!!movingOrg && ( + setMovingOrg(undefined)} + onSuccess={refetchOrgs} + /> + )} + {!!manageMemberOrg && ( + setManageMemberOrg(undefined)} + /> + )} + + + ); } diff --git a/projects/app/src/pages/account/team/components/context.tsx b/projects/app/src/pages/account/team/components/context.tsx index ff50e0cf9..c4fd1ad05 100644 --- a/projects/app/src/pages/account/team/components/context.tsx +++ b/projects/app/src/pages/account/team/components/context.tsx @@ -26,7 +26,7 @@ type TeamModalContextType = { refetchTeams: () => void; refetchGroups: () => void; teamSize: number; - MemberScrollData?: ReturnType['ScrollData']; + MemberScrollData: ReturnType['ScrollData']; }; export const TeamContext = createContext({ @@ -51,7 +51,7 @@ export const TeamContext = createContext({ }, teamSize: 0, - MemberScrollData: undefined + MemberScrollData: () => <> }); export const TeamModalContextProvider = ({ children }: { children: ReactNode }) => { diff --git a/projects/app/src/pages/account/team/index.tsx b/projects/app/src/pages/account/team/index.tsx index a21078d2a..6c6a5e185 100644 --- a/projects/app/src/pages/account/team/index.tsx +++ b/projects/app/src/pages/account/team/index.tsx @@ -61,72 +61,81 @@ const Team = () => { return ( - {/* header */} - - - - - - {t('account:team')} - - - - - - {userInfo?.team?.role === TeamMemberRoleEnum.owner && ( - - { - if (!userInfo?.team) return; - setEditTeamData({ - id: userInfo.team.teamId, - name: userInfo.team.teamName, - avatar: userInfo.team.avatar - }); - }} - /> + + {/* header */} + + + + + + {t('account:team')} + - )} + + + + {userInfo?.team?.role === TeamMemberRoleEnum.owner && ( + + { + if (!userInfo?.team) return; + setEditTeamData({ + id: userInfo.team.teamId, + name: userInfo.team.teamName, + avatar: userInfo.team.avatar + }); + }} + /> + + )} + + + + {t('account_team:total_team_members', { amount: teamSize })} + + {/* table */} - {t('account_team:total_team_members', { amount: teamSize })} + {teamTab === TeamTabEnum.member && } + {teamTab === TeamTabEnum.org && } + {teamTab === TeamTabEnum.group && } + {teamTab === TeamTabEnum.permission && } - - {/* table */} - - {teamTab === TeamTabEnum.member && } - {teamTab === TeamTabEnum.org && } - {teamTab === TeamTabEnum.group && } - {teamTab === TeamTabEnum.permission && } - ); }; diff --git a/projects/app/src/pages/api/admin/initv4819.ts b/projects/app/src/pages/api/admin/initv4819.ts index cbdfb93a4..626fbdaa0 100644 --- a/projects/app/src/pages/api/admin/initv4819.ts +++ b/projects/app/src/pages/api/admin/initv4819.ts @@ -1,4 +1,5 @@ import { NextAPI } from '@/service/middleware/entry'; +import { mongoSessionRun } from '@fastgpt/service/common/mongo/sessionRun'; import { authCert } from '@fastgpt/service/support/permission/auth/common'; import { MongoUser } from '@fastgpt/service/support/user/schema'; import { MongoTeamMember } from '@fastgpt/service/support/user/team/teamMemberSchema'; @@ -19,18 +20,35 @@ export default NextAPI(handler); const moveUserAvatar = async () => { try { - const users = await MongoUser.find({}); + const users = await MongoUser.find({}, '_id avatar'); + console.log('Total users:', users.length); + let success = 0; for await (const user of users) { - await MongoTeamMember.updateOne( - { - _id: user._id - }, - { - avatar: (user as any).avatar // 删除 avatar 字段, 因为 Type 改了,所以这里不能直接写 user.avatar - } - ); + // @ts-ignore + if (!user.avatar) continue; + try { + await mongoSessionRun(async (session) => { + await MongoTeamMember.updateOne( + { + userId: user._id + }, + { + $set: { + avatar: (user as any).avatar // 删除 avatar 字段, 因为 Type 改了,所以这里不能直接写 user.avatar + } + }, + { session } + ); + // @ts-ignore + user.avatar = undefined; + await user.save({ session }); + }); + success++; + console.log('Move avatar success:', success); + } catch (error) { + console.error(error); + } } - console.log('Move avatar success:', users.length); } catch (error) { console.error(error); } diff --git a/projects/app/src/pages/app/detail/components/PublishHistoriesSlider.tsx b/projects/app/src/pages/app/detail/components/PublishHistoriesSlider.tsx index eeb6429b4..e367e1963 100644 --- a/projects/app/src/pages/app/detail/components/PublishHistoriesSlider.tsx +++ b/projects/app/src/pages/app/detail/components/PublishHistoriesSlider.tsx @@ -4,7 +4,7 @@ import { getWorkflowVersionList, updateAppVersion } from '@/web/core/app/api/version'; -import { useVirtualScrollPagination } from '@fastgpt/web/hooks/useScrollPagination'; +import { useScrollPagination } from '@fastgpt/web/hooks/useScrollPagination'; import CustomRightDrawer from '@fastgpt/web/components/common/MyDrawer/CustomRightDrawer'; import { useTranslation } from 'next-i18next'; import { Box, BoxProps, Button, Flex, Input } from '@chakra-ui/react'; @@ -22,7 +22,6 @@ import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useToast } from '@fastgpt/web/hooks/useToast'; import type { AppVersionSchemaType, VersionListItemType } from '@fastgpt/global/core/app/version'; import type { SimpleAppSnapshotType } from './SimpleApp/useSnapshots'; -import UserBox from '@fastgpt/web/components/common/UserBox'; const PublishHistoriesSlider = ({ onClose, @@ -183,18 +182,18 @@ const TeamCloud = ({ const { t } = useTranslation(); const { appDetail } = useContextSelector(AppContext, (v) => v); - const { scrollDataList, ScrollList, isLoading, setData } = useVirtualScrollPagination( - getWorkflowVersionList, - { - itemHeight: 40, - overscan: 20, - - pageSize: 30, - defaultParams: { - appId: appDetail._id - } - } - ); + const { + ScrollData, + data: scrollDataList, + setData, + isLoading + } = useScrollPagination(getWorkflowVersionList, { + pageSize: 30, + params: { + appId: appDetail._id + }, + refreshDeps: [appDetail._id] + }); const [editIndex, setEditIndex] = useState(undefined); const [hoveredIndex, setHoveredIndex] = useState(undefined); @@ -231,14 +230,13 @@ const TeamCloud = ({ ); return ( - - {scrollDataList.map((data, index) => { - const item = data.data; - const firstPublishedIndex = scrollDataList.findIndex((data) => data.data.isPublish); + + {scrollDataList.map((item, index) => { + const firstPublishedIndex = scrollDataList.findIndex((data) => data.isPublish); return ( {() => ( - - - - {formatTime2YMDHMS(item.time)} + + + + + + + {item.sourceMember.name} + {item.sourceMember.status === 'leave' && ( + {t('common:user_leaved')} + )} + + + {formatTime2YMDHMS(item.time)} + )} @@ -340,6 +353,6 @@ const TeamCloud = ({ ); })} - + ); };