import React, { useMemo, useState } from 'react'; import MyIcon from '@fastgpt/web/components/common/Icon'; import { Box, Button, Flex, Grid, ModalBody, ModalFooter } from '@chakra-ui/react'; import { useTranslation } from 'next-i18next'; import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants'; import { postCheckStandardSub, postUpdateStandardSub } from '@/web/support/wallet/sub/api'; import { useSystemStore } from '@/web/common/system/useSystemStore'; import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants'; import { StandardSubPlanParams } from '@fastgpt/global/support/wallet/sub/api'; import { useRequest } from '@/web/common/hooks/useRequest'; import { StandardSubPlanUpdateResponse } from '@fastgpt/global/support/wallet/sub/api.d'; import { useToast } from '@fastgpt/web/hooks/useToast'; import { formatStorePrice2Read } from '@fastgpt/global/support/wallet/usage/tools'; import { TeamSubSchema } from '@fastgpt/global/support/wallet/sub/type'; import MyModal from '@/components/MyModal'; import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal'; import { getWxPayQRCode } from '@/web/support/wallet/bill/api'; import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants'; import StandardPlanContentList from '@/components/support/wallet/StandardPlanContentList'; type ConfirmPayModalProps = { teamBalance: number; totalPrice: number; payPrice: number; planProps: StandardSubPlanParams; }; const Standard = ({ standardPlan, refetchTeamSubPlan }: { standardPlan?: TeamSubSchema; refetchTeamSubPlan: () => void; }) => { const { t } = useTranslation(); const { subPlans, feConfigs } = useSystemStore(); const { toast } = useToast(); const [confirmPayData, setConfirmPayData] = useState(); const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month); const standardSubList = useMemo(() => { return subPlans?.standard ? Object.entries(subPlans.standard).map(([level, value]) => { return { price: value.price * (selectSubMode === SubModeEnum.month ? 1 : 10), level: level as `${StandardSubLevelEnum}`, ...standardSubLevelMap[level as `${StandardSubLevelEnum}`], maxTeamMember: value.maxTeamMember, maxAppAmount: value.maxAppAmount, maxDatasetAmount: value.maxDatasetAmount, chatHistoryStoreDuration: value.chatHistoryStoreDuration, maxDatasetSize: value.maxDatasetSize, permissionCustomApiKey: value.permissionCustomApiKey, permissionCustomCopyright: value.permissionCustomCopyright, trainingWeight: value.trainingWeight, permissionReRank: value.permissionReRank, totalPoints: value.totalPoints * (selectSubMode === SubModeEnum.month ? 1 : 12), permissionWebsiteSync: value.permissionWebsiteSync }; }) : []; }, [subPlans?.standard, selectSubMode]); const { mutate: onclickUpdateStandardPlan, isLoading: isUpdatingStandardPlan } = useRequest({ mutationFn: (data: StandardSubPlanParams) => postUpdateStandardSub(data), onSuccess() { refetchTeamSubPlan(); }, successToast: t('support.wallet.subscription.Standard update success'), errorToast: t('support.wallet.subscription.Standard update fail') }); const { mutate: onclickPreCheckStandPlan, isLoading: isCheckingStandardPlan } = useRequest({ mutationFn: (data: StandardSubPlanParams) => postCheckStandardSub(data), onSuccess(res: StandardSubPlanUpdateResponse) { if (res.payPrice === undefined) { onclickUpdateStandardPlan({ level: res.nextSubLevel, mode: res.nextMode }); } else { setConfirmPayData({ teamBalance: res.teamBalance, totalPrice: res.planPrice, payPrice: res.payPrice, planProps: { level: res.nextSubLevel, mode: res.nextMode } }); } } }); return ( {t('support.wallet.subscription.Sub plan')} {t('support.wallet.subscription.Sub plan tip')} {t('support.wallet.subscription.mode.Year')} ({t('support.wallet.subscription.mode.Year sale')}) ), value: SubModeEnum.year } ]} value={selectSubMode} onChange={(e) => setSelectSubMode(e as `${SubModeEnum}`)} /> {/* card */} {standardSubList.map((item) => { const isCurrentPlan = item.level === standardPlan?.currentSubLevel && selectSubMode === standardPlan?.currentMode; return ( {t(item.label)} ¥{item.price} {t(item.desc, { title: feConfigs?.systemTitle })} {(() => { if ( item.level === StandardSubLevelEnum.free && selectSubMode === SubModeEnum.year ) { return ( ); } if ( item.level === standardPlan?.nextSubLevel && selectSubMode === standardPlan?.nextMode ) { return ( ); } if (isCurrentPlan) { return ( ); } return ( ); })()} {/* function list */} ); })} {!!confirmPayData && ( setConfirmPayData(undefined)} onConfirmPay={() => onclickUpdateStandardPlan(confirmPayData.planProps)} /> )} ); }; export default React.memo(Standard); const RowTabs = ({ list, value, onChange }: { list: { icon?: string; label: string | React.ReactNode; value: string; }[]; value: string; onChange: (e: string) => void; }) => { return ( {list.map((item) => ( onChange(item.value) })} > {item.icon && } {item.label} ))} ); }; const ConfirmPayModal = ({ teamBalance, totalPrice, payPrice, onClose, onConfirmPay }: ConfirmPayModalProps & { onClose: () => void; onConfirmPay: () => void }) => { const { t } = useTranslation(); const [qrPayData, setQRPayData] = useState(); const formatPayPrice = Math.ceil(formatStorePrice2Read(payPrice)); const formatTeamBalance = Math.floor(formatStorePrice2Read(teamBalance)); const { mutate: handleClickPay, isLoading } = useRequest({ mutationFn: async (amount: number) => { // 获取支付二维码 return getWxPayQRCode({ type: BillTypeEnum.balance, balance: amount }); }, onSuccess(res) { setQRPayData({ readPrice: res.readPrice, codeUrl: res.codeUrl, billId: res.billId }); } }); return ( 新套餐价格 {formatStorePrice2Read(totalPrice)}元 旧套餐余额 {Math.floor(formatStorePrice2Read(totalPrice - payPrice))}元 需支付 {formatPayPrice}元 账号余额: {formatTeamBalance}元 {teamBalance >= payPrice ? ( ) : ( )} {!!qrPayData && } ); };