import React, { useCallback, useEffect, useMemo } from 'react'; import { Box, Flex, Button, useDisclosure, useTheme, Input, Link, Progress, Grid, BoxProps } from '@chakra-ui/react'; import { useForm } from 'react-hook-form'; import { UserUpdateParams } from '@/types/user'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { useUserStore } from '@/web/support/user/useUserStore'; import type { UserType } from '@fastgpt/global/support/user/type.d'; import { useQuery } from '@tanstack/react-query'; import dynamic from 'next/dynamic'; import { useSelectFile } from '@/web/common/file/hooks/useSelectFile'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { useTranslation } from 'next-i18next'; import Avatar from '@fastgpt/web/components/common/Avatar'; import MyIcon from '@fastgpt/web/components/common/Icon'; import MyTooltip from '@fastgpt/web/components/common/MyTooltip'; import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; import { putUpdateMemberName } from '@/web/support/user/team/api'; import { getDocPath } from '@/web/common/system/doc'; import { StandardSubLevelEnum, standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants'; import { formatTime2YMD } from '@fastgpt/global/common/string/time'; import { getExtraPlanCardRoute } from '@/web/support/wallet/sub/constants'; import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList'; import QuestionTip from '@fastgpt/web/components/common/MyTooltip/QuestionTip'; import { useSystem } from '@fastgpt/web/hooks/useSystem'; import { getWebReqUrl } from '@fastgpt/web/common/system/utils'; import AccountContainer from '@/pageComponents/account/AccountContainer'; import { serviceSideProps } from '@fastgpt/web/common/system/nextjs'; import { useRouter } from 'next/router'; import TeamSelector from '@/pageComponents/account/TeamSelector'; import { getWorkorderURL } from '@/web/common/workorder/api'; import { useRequest2 } from '@fastgpt/web/hooks/useRequest'; import { useMount } from 'ahooks'; const StandDetailModal = dynamic( () => import('@/pageComponents/account/info/standardDetailModal'), { ssr: false } ); const ConversionModal = dynamic(() => import('@/pageComponents/account/info/ConversionModal')); const UpdatePswModal = dynamic(() => import('@/pageComponents/account/info/UpdatePswModal')); const UpdateContact = dynamic(() => import('@/components/support/user/inform/UpdateContactModal')); const CommunityModal = dynamic(() => import('@/components/CommunityModal')); const ModelPriceModal = dynamic(() => import('@/components/core/ai/ModelTable').then((mod) => mod.ModelPriceModal) ); const Info = () => { const { isPc } = useSystem(); const { teamPlanStatus, initUserInfo } = useUserStore(); const standardPlan = teamPlanStatus?.standardConstants; const { isOpen: isOpenContact, onClose: onCloseContact, onOpen: onOpenContact } = useDisclosure(); useMount(() => { initUserInfo(); }); return ( {isPc ? ( {!!standardPlan && ( )} ) : ( <> {standardPlan && } )} {isOpenContact && } ); }; export async function getServerSideProps(content: any) { return { props: { ...(await serviceSideProps(content, ['account', 'account_info', 'user'])) } }; } export default React.memo(Info); const MyInfo = ({ onOpenContact }: { onOpenContact: () => void }) => { const theme = useTheme(); const { feConfigs } = useSystemStore(); const { t } = useTranslation(); const { userInfo, updateUserInfo, teamPlanStatus, initUserInfo } = useUserStore(); const { reset } = useForm({ defaultValues: userInfo as UserType }); const standardPlan = teamPlanStatus?.standardConstants; const { isPc } = useSystem(); const { toast } = useToast(); const { isOpen: isOpenConversionModal, onClose: onCloseConversionModal, onOpen: onOpenConversionModal } = useDisclosure(); const { isOpen: isOpenUpdatePsw, onClose: onCloseUpdatePsw, onOpen: onOpenUpdatePsw } = useDisclosure(); const { isOpen: isOpenUpdateContact, onClose: onCloseUpdateContact, onOpen: onOpenUpdateContact } = useDisclosure(); const { File, onOpen: onOpenSelectFile, onSelectImage } = useSelectFile({ fileType: '.jpg,.png', multiple: false }); const onclickSave = useCallback( async (data: UserType) => { await updateUserInfo({ avatar: data.avatar, timezone: data.timezone }); reset(data); toast({ title: t('account_info:update_success_tip'), status: 'success' }); }, [reset, t, toast, updateUserInfo] ); const labelStyles: BoxProps = { flex: '0 0 80px', fontSize: 'sm', color: 'myGray.900' }; const isSyncMember = feConfigs.register_method?.includes('sync'); return ( {/* user info */} {isPc && ( {t('account_info:personal_information')} )} {isPc ? ( {t('account_info:avatar')}:  ) : ( {t('account_info:change')} )} {feConfigs?.isPlus && ( {t('account_info:member_name')}:  { const val = e.target.value; if (val === userInfo?.team?.memberName) return; try { await putUpdateMemberName(val); initUserInfo(); } catch (error) {} }} /> )} {t('account_info:user_account')}:  {userInfo?.username} {feConfigs?.isPlus && ( {t('account_info:password')}:  ***** )} {feConfigs?.isPlus && ( {t('common:contact_way')}:  {userInfo?.contact ? userInfo?.contact : t('account_info:please_bind_contact')} )} {feConfigs.isPlus && ( {t('account_info:user_team_team_name')}:  )} {feConfigs?.isPlus && (userInfo?.team?.balance ?? 0) > 0 && ( {t('account_info:team_balance')}:  {formatStorePrice2Read(userInfo?.team?.balance).toFixed(3)}{' '} {t('account_info:yuan')} {userInfo?.permission.hasManagePer && !!standardPlan && ( )} )} {isOpenConversionModal && ( )} {isOpenUpdatePsw && } {isOpenUpdateContact && } onSelectImage(e, { maxW: 300, maxH: 300, callback: (src) => { if (!userInfo) return; onclickSave({ ...userInfo, avatar: src }); } }) } /> ); }; const PlanUsage = () => { const router = useRouter(); const { t } = useTranslation(); const { userInfo, initUserInfo, teamPlanStatus } = useUserStore(); const { subPlans } = useSystemStore(); const { reset } = useForm({ defaultValues: userInfo as UserType }); const { isOpen: isOpenStandardModal, onClose: onCloseStandardModal, onOpen: onOpenStandardModal } = useDisclosure(); const planName = useMemo(() => { if (!teamPlanStatus?.standard?.currentSubLevel) return ''; return standardSubLevelMap[teamPlanStatus.standard.currentSubLevel].label; }, [teamPlanStatus?.standard?.currentSubLevel]); const standardPlan = teamPlanStatus?.standard; const isFreeTeam = useMemo(() => { if (!teamPlanStatus || !teamPlanStatus?.standardConstants) return false; const hasExtraDatasetSize = teamPlanStatus.datasetMaxSize > teamPlanStatus.standardConstants.maxDatasetSize; const hasExtraPoints = teamPlanStatus.totalPoints > teamPlanStatus.standardConstants.totalPoints; if ( teamPlanStatus?.standard?.currentSubLevel === StandardSubLevelEnum.free && !hasExtraDatasetSize && !hasExtraPoints ) { return true; } return false; }, [teamPlanStatus]); useQuery(['init'], initUserInfo, { onSuccess(res) { reset(res); } }); const datasetUsageMap = useMemo(() => { if (!teamPlanStatus) { return { colorScheme: 'green', value: 0, maxSize: t('account_info:unlimited'), usedSize: 0 }; } const rate = teamPlanStatus.usedDatasetSize / teamPlanStatus.datasetMaxSize; const colorScheme = (() => { if (rate < 0.5) return 'green'; if (rate < 0.8) return 'yellow'; return 'red'; })(); return { colorScheme, value: rate * 100, maxSize: teamPlanStatus.datasetMaxSize || t('account_info:unlimited'), usedSize: teamPlanStatus.usedDatasetSize }; }, [teamPlanStatus, t]); const aiPointsUsageMap = useMemo(() => { if (!teamPlanStatus) { return { colorScheme: 'green', value: 0, maxSize: t('account_info:unlimited'), usedSize: 0 }; } const rate = teamPlanStatus.usedPoints / teamPlanStatus.totalPoints; const colorScheme = (() => { if (rate < 0.5) return 'green'; if (rate < 0.8) return 'yellow'; return 'red'; })(); return { colorScheme, value: rate * 100, max: teamPlanStatus.totalPoints ? teamPlanStatus.totalPoints : t('account_info:unlimited'), used: teamPlanStatus.usedPoints ? Math.round(teamPlanStatus.usedPoints) : 0 }; }, [teamPlanStatus, t]); return standardPlan ? ( {t('account_info:package_and_usage')} {({ onOpen }) => ( )} {t('account_info:current_package')} {t(planName as any)} {isFreeTeam && ( {t('account_info:account_knowledge_base_cleanup_warning')} )} {standardPlan.currentSubLevel !== StandardSubLevelEnum.free && ( {t('account_info:package_expiry_time')}: {formatTime2YMD(standardPlan?.expiredTime)} )} {t('account_info:resource_usage')} {t('account_info:standard_package_and_extra_resource_package')} {t('account_info:purchase_extra_package')} {t('account_info:knowledge_base_capacity')} {datasetUsageMap.usedSize}/{datasetUsageMap.maxSize} {t('account_info:ai_points_usage')} {aiPointsUsageMap.used}/{aiPointsUsageMap.max} {isOpenStandardModal && } ) : null; }; const ButtonStyles = { bg: 'white', py: 3, px: 6, border: 'sm', borderWidth: '1.5px', borderRadius: 'md', display: 'flex', alignItems: 'center', cursor: 'pointer', userSelect: 'none' as any, fontSize: 'sm' }; const Other = ({ onOpenContact }: { onOpenContact: () => void }) => { const { feConfigs } = useSystemStore(); const { teamPlanStatus } = useUserStore(); const { t } = useTranslation(); const { isPc } = useSystem(); const { runAsync: onFeedback } = useRequest2(getWorkorderURL, { manual: true, onSuccess(data) { if (data) { window.open(data.redirectUrl); } } }); return ( {feConfigs?.docUrl && ( {t('account_info:help_document')} )} {!isPc && feConfigs?.navbarItems ?.filter((item) => item.isActive) .map((item) => ( window.open(item.url, '_blank')}> {item.name} ))} {feConfigs?.concatMd && ( {t('account_info:contact_us')} )} {feConfigs?.show_workorder && teamPlanStatus && teamPlanStatus.standard?.currentSubLevel !== StandardSubLevelEnum.free && ( {t('common:question_feedback')} )} ); };