diff --git a/packages/web/i18n/en/common.json b/packages/web/i18n/en/common.json
index e4530f447ade..91b3310b28f0 100644
--- a/packages/web/i18n/en/common.json
+++ b/packages/web/i18n/en/common.json
@@ -891,7 +891,7 @@
"pay_corporate_payment": "Payment to the public",
"pay_money": "Amount payable",
"pay_success": "Payment successfully",
- "pay_year_tip": "Pay 10 months, enjoy 1 year!",
+ "pay_year_tip": "Pay {{count}} months, enjoy 1 year!",
"permission.Collaborator": "Collaborator",
"permission.Manage": "Manage",
"permission.No InheritPermission": "Permission Inheritance Restricted",
@@ -1051,6 +1051,10 @@
"support.wallet.subscription.Extra plan": "Extra Resource Pack",
"support.wallet.subscription.Extra plan tip": "When the standard package is not enough, you can purchase extra resource packs to continue using",
"support.wallet.subscription.FAQ": "FAQ",
+ "support.wallet.subscription.Basic plan tab": "Basic Plan",
+ "support.wallet.subscription.Extra points tab": "Extra Points",
+ "support.wallet.subscription.Extra dataset tab": "Extra Dataset Index",
+ "support.wallet.subscription.Purchase plan": "Purchase Plan",
"support.wallet.subscription.Sub plan": "Subscription Package",
"support.wallet.subscription.Sub plan tip": "Free to use [{{title}}] or upgrade to a higher package",
"support.wallet.subscription.Sub plan tip wecom": "Purchase a plan to enjoy application services",
@@ -1061,7 +1065,9 @@
"support.wallet.subscription.ai_model": "AI Language Model",
"support.wallet.subscription.extra_plan_disabled_tip": "Please subscribe to a plan first before purchasing extra resource packs.",
"support.wallet.subscription.mode.Month": "Month",
+ "support.wallet.subscription.mode.Month pay": "Monthly",
"support.wallet.subscription.mode.Year": "Year",
+ "support.wallet.subscription.mode.Year pay": "Yearly",
"support.wallet.subscription.per_year": "/ year",
"support.wallet.subscription.point": " Points",
"support.wallet.subscription.standardSubLevel.advanced": "Advanced",
diff --git a/packages/web/i18n/zh-CN/account.json b/packages/web/i18n/zh-CN/account.json
index 7b5b813dcac2..38daa37a0e35 100644
--- a/packages/web/i18n/zh-CN/account.json
+++ b/packages/web/i18n/zh-CN/account.json
@@ -19,7 +19,7 @@
"custom_config_details": "定制配置详情",
"day": "天",
"extra_ai_points": "额外 AI 积分",
- "extra_dataset_size": "额外知识库容量",
+ "extra_dataset_size": "额外知识库索引量",
"generation_time": "生成时间",
"has_invoice": "是否已开票",
"hour": "小时",
diff --git a/packages/web/i18n/zh-CN/common.json b/packages/web/i18n/zh-CN/common.json
index 22974c251abc..ac62aa0e043f 100644
--- a/packages/web/i18n/zh-CN/common.json
+++ b/packages/web/i18n/zh-CN/common.json
@@ -112,7 +112,7 @@
"bill_expired": "订单已过期",
"bill_not_found": "订单不存在",
"bill_not_pay_processed": "非在线订单",
- "button.extra_dataset_size_tip": "您正在购买【额外知识库容量】",
+ "button.extra_dataset_size_tip": "您正在购买【额外知识库索引量】",
"button.extra_points_tip": "您正在购买【额外 AI 积分】",
"can_copy_content_tip": "无法使用浏览器自动复制,请手动复制下面内容",
"cancel_bill": "取消",
@@ -891,7 +891,7 @@
"pay_corporate_payment": "对公支付",
"pay_money": "应付金额",
"pay_success": "支付成功",
- "pay_year_tip": "支付 10 个月,畅享 1 年!",
+ "pay_year_tip": "支付 {{count}} 个月,畅享一年!",
"permission.Collaborator": "协作者",
"permission.Manage": "管理",
"permission.No InheritPermission": "已限制权限,不再继承父级文件夹的权限,",
@@ -1023,7 +1023,7 @@
"support.wallet.App_amount_not_sufficient": "您的应用数量已达上限,请升级套餐后继续使用。",
"support.wallet.Buy": "购买",
"support.wallet.Dataset_amount_not_sufficient": "您的知识库数量已达上限,请升级套餐后继续使用。",
- "support.wallet.Dataset_not_sufficient": "您的知识库容量不足,请先升级套餐或购买额外知识库容量后继续使用。",
+ "support.wallet.Dataset_not_sufficient": "您的知识库容量不足,请先升级套餐或购买额外知识库索引量后继续使用。",
"support.wallet.Not sufficient": "您的 AI 积分不足,请先升级套餐或购买额外 AI 积分后继续使用。",
"support.wallet.Not_sufficient_contact_admin": "您的 AI 积分不足,请联系团队管理员。",
"support.wallet.Team_member_over_size": "您的团队成员数量已达上限,请升级套餐后继续使用。",
@@ -1046,11 +1046,15 @@
"support.wallet.subscription.Dataset size": "知识库索引量",
"support.wallet.subscription.Extra ai points": "额外 AI 积分",
"support.wallet.subscription.Extra dataset description": "支持根据实际需求为知识库索引量延长有效期",
- "support.wallet.subscription.Extra dataset size": "额外知识库容量",
+ "support.wallet.subscription.Extra dataset size": "额外知识库索引量",
"support.wallet.subscription.Extra dataset unit": "组/1个月",
"support.wallet.subscription.Extra plan": "额外资源包",
- "support.wallet.subscription.Extra plan tip": "标准套餐不够时,您可以购买额外资源包继续使用",
+ "support.wallet.subscription.Extra plan tip": "基础套餐容量不足时,可购买额外资源包继续使用",
"support.wallet.subscription.FAQ": "常见问题",
+ "support.wallet.subscription.Basic plan tab": "基础套餐",
+ "support.wallet.subscription.Extra points tab": "额外积分",
+ "support.wallet.subscription.Extra dataset tab": "额外知识库索引量",
+ "support.wallet.subscription.Purchase plan": "购买套餐",
"support.wallet.subscription.Sub plan": "订阅套餐",
"support.wallet.subscription.Sub plan tip": "免费使用【{{title}}】或升级更高的套餐",
"support.wallet.subscription.Sub plan tip wecom": "购买套餐以享受应用服务",
@@ -1061,7 +1065,9 @@
"support.wallet.subscription.ai_model": "AI语言模型",
"support.wallet.subscription.extra_plan_disabled_tip": "如需购买额外资源包,请先订阅套餐。",
"support.wallet.subscription.mode.Month": "按月",
+ "support.wallet.subscription.mode.Month pay": "按月付",
"support.wallet.subscription.mode.Year": "按年",
+ "support.wallet.subscription.mode.Year pay": "按年付",
"support.wallet.subscription.per_year": "/ 年",
"support.wallet.subscription.point": "积分",
"support.wallet.subscription.standardSubLevel.advanced": "高级版",
diff --git a/packages/web/i18n/zh-Hant/account.json b/packages/web/i18n/zh-Hant/account.json
index 7741f372fad7..867890e1aa06 100644
--- a/packages/web/i18n/zh-Hant/account.json
+++ b/packages/web/i18n/zh-Hant/account.json
@@ -19,7 +19,7 @@
"custom_config_details": "定制配置詳情",
"day": "天",
"extra_ai_points": "AI 積分運算標準",
- "extra_dataset_size": "額外知識庫容量",
+ "extra_dataset_size": "額外知識庫索引量",
"generation_time": "生成時間",
"has_invoice": "是否已開票",
"hour": "小時",
diff --git a/packages/web/i18n/zh-Hant/common.json b/packages/web/i18n/zh-Hant/common.json
index 793e88a02b7f..2ed2178b5730 100644
--- a/packages/web/i18n/zh-Hant/common.json
+++ b/packages/web/i18n/zh-Hant/common.json
@@ -111,7 +111,7 @@
"bill_expired": "訂單已過期",
"bill_not_found": "訂單不存在",
"bill_not_pay_processed": "非在線訂單",
- "button.extra_dataset_size_tip": "您正在購買【額外知識庫容量】",
+ "button.extra_dataset_size_tip": "您正在購買【額外知識庫索引量】",
"button.extra_points_tip": "您正在購買【額外 AI 積分】",
"can_copy_content_tip": "無法使用瀏覽器自動複製,請手動複製下面內容",
"cancel_bill": "取消",
@@ -881,7 +881,7 @@
"pay_corporate_payment": "對公支付",
"pay_money": "應付金額",
"pay_success": "支付成功",
- "pay_year_tip": "支付 10 個月,暢享 1 年!",
+ "pay_year_tip": "支付 {{count}} 個月,暢享一年!",
"permission.Collaborator": "協作者",
"permission.Manage": "管理",
"permission.No InheritPermission": "已限制權限,不再繼承上層資料夾的權限",
@@ -1012,7 +1012,7 @@
"support.wallet.App_amount_not_sufficient": "您的應用數量已達上限,請升級套餐後繼續使用。",
"support.wallet.Buy": "購買",
"support.wallet.Dataset_amount_not_sufficient": "您的知識庫數量已達上限,請升級套餐後繼續使用。",
- "support.wallet.Dataset_not_sufficient": "您的知識庫容量不足,請先升級套餐或購買額外知識庫容量後繼續使用。",
+ "support.wallet.Dataset_not_sufficient": "您的知識庫容量不足,請先升級套餐或購買額外知識庫索引量後繼續使用。",
"support.wallet.Not sufficient": "您的 AI 點數不足,請先升級方案或購買額外 AI 點數後繼續使用。",
"support.wallet.Not_sufficient_contact_admin": "您的 AI 點數不足,請聯絡團隊管理員。",
"support.wallet.Team_member_over_size": "您的團隊成員數量已達上限,請升級套餐後繼續使用。",
@@ -1035,11 +1035,15 @@
"support.wallet.subscription.Dataset size": "知識庫索引量",
"support.wallet.subscription.Extra ai points": "額外 AI 點數",
"support.wallet.subscription.Extra dataset description": "支持根據實際需求為知識庫索引量延長有效期",
- "support.wallet.subscription.Extra dataset size": "額外知識庫容量",
+ "support.wallet.subscription.Extra dataset size": "額外知識庫索引量",
"support.wallet.subscription.Extra dataset unit": "組/1個月",
"support.wallet.subscription.Extra plan": "額外資源包",
- "support.wallet.subscription.Extra plan tip": "當標準方案不足時,您可以購買額外資源包繼續使用",
+ "support.wallet.subscription.Extra plan tip": "基礎套餐容量不足時,可購買額外資源包繼續使用",
"support.wallet.subscription.FAQ": "常見問題",
+ "support.wallet.subscription.Basic plan tab": "基礎套餐",
+ "support.wallet.subscription.Extra points tab": "額外積分",
+ "support.wallet.subscription.Extra dataset tab": "額外知識庫索引量",
+ "support.wallet.subscription.Purchase plan": "購買套餐",
"support.wallet.subscription.Sub plan": "訂閱方案",
"support.wallet.subscription.Sub plan tip": "免費使用【{{title}}】或升級更進階的方案",
"support.wallet.subscription.Sub plan tip wecom": "購買方案以享受應用服務",
@@ -1050,7 +1054,9 @@
"support.wallet.subscription.ai_model": "AI 語言模型",
"support.wallet.subscription.extra_plan_disabled_tip": "如需購買額外資源包,請先訂閱方案。",
"support.wallet.subscription.mode.Month": "按月",
+ "support.wallet.subscription.mode.Month pay": "按月付",
"support.wallet.subscription.mode.Year": "按年",
+ "support.wallet.subscription.mode.Year pay": "按年付",
"support.wallet.subscription.per_year": "/ 年",
"support.wallet.subscription.point": "點數",
"support.wallet.subscription.standardSubLevel.advanced": "高級版",
diff --git a/projects/app/public/imgs/price/extraDatasetIcon.svg b/projects/app/public/imgs/price/extraDatasetIcon.svg
new file mode 100644
index 000000000000..2f3f5e1038c7
--- /dev/null
+++ b/projects/app/public/imgs/price/extraDatasetIcon.svg
@@ -0,0 +1,37 @@
+
diff --git a/projects/app/src/pageComponents/price/ExtraPlan.tsx b/projects/app/src/pageComponents/price/ExtraPlan.tsx
index 7bff78ed2025..87b10f4f6148 100644
--- a/projects/app/src/pageComponents/price/ExtraPlan.tsx
+++ b/projects/app/src/pageComponents/price/ExtraPlan.tsx
@@ -17,7 +17,13 @@ import { formatActivityExpirationTime } from './utils';
import { useUserStore } from '@/web/support/user/useUserStore';
import { StandardSubLevelEnum } from '@fastgpt/global/support/wallet/sub/constants';
-const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
+const ExtraPlan = ({
+ onPaySuccess,
+ mode = 'all'
+}: {
+ onPaySuccess?: () => void;
+ mode?: 'all' | 'points' | 'dataset';
+}) => {
const { t, i18n } = useTranslation();
const { toast } = useToast();
const { subPlans } = useSystemStore();
@@ -119,388 +125,468 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
subPlans?.activityExpirationTime
);
+ const showPoints = mode === 'all' || mode === 'points';
+ const showDataset = mode === 'all' || mode === 'dataset';
+ const isDualCardLayout = mode === 'all';
+
+ const dualCardStyle = {
+ borderRadius: '16px',
+ borderWidth: '1px',
+ borderColor: '#E8EBF0',
+ bg: '#FFF',
+ boxShadow: '0 1px 2px 0 rgba(19, 51, 107, 0.10), 0 0 1px 0 rgba(19, 51, 107, 0.15)'
+ } as const;
+
+ const dualCardBaseProps = {
+ display: 'flex' as const,
+ flexDirection: 'column' as const,
+ alignItems: 'flex-start' as const,
+ w: ['100%', '483.016px'],
+ h: ['auto', '488px'],
+ p: ['16px', '24px 32px'],
+ flexShrink: 0,
+ ...dualCardStyle
+ };
+
return (
-
-
-
- {subPlans?.activityExpirationTime && (
- <>
-
-
-
- >
- )}
+
+
+ {showPoints && (
- {t('common:support.wallet.subscription.Extra ai points')}
-
- {activityExpirationTime}
-
-
-
- {extraPointsPackages.map((pkg, index) => (
- 6 ? 1 : 2}
- px={[3, 4]}
- borderRadius={['8px', 'sm']}
- borderWidth={'1px'}
- borderColor={selectedPackageIndex === index ? '#3E78FF' : 'myGray.200'}
- bg={selectedPackageIndex === index ? 'primary.25' : 'white'}
- cursor={'pointer'}
- _hover={{
- borderColor: '#3E78FF',
- bg: 'primary.25'
- }}
- onClick={() => setSelectedPackageIndex(index)}
- transition={'all 0.2s'}
- position={'relative'}
- overflow={'hidden'}
- >
- {!!pkg.activityBonusPoints && (
-
- +{formatNumberWithUnit(pkg.activityBonusPoints, i18n.language)}
-
- )}
-
- {formatNumberWithUnit(pkg.points, i18n.language)}{' '}
-
- {t('common:support.wallet.subscription.point')}
-
-
+ {subPlans?.activityExpirationTime && (
+ <>
- {t('common:invalid_time') + ' '}
- {getMonthText(pkg.month)}
-
-
- ))}
-
-
-
+ position={'absolute'}
+ top={8}
+ left={'36%'}
+ width={'55px'}
+ height={'64px'}
+ zIndex={0}
+ bgImage={'url(/imgs/system/extraSnowflake1.svg)'}
+ backgroundSize="100% 100%"
+ backgroundRepeat="no-repeat"
+ />
+
+
+ >
+ )}
- {t('common:support.wallet.subscription.total_points')}
-
-
- {selectedPackageIndex !== undefined && extraPointsPackages[selectedPackageIndex]
- ? formatNumberWithUnit(
- extraPointsPackages[selectedPackageIndex].points +
- (extraPointsPackages[selectedPackageIndex]?.activityBonusPoints || 0),
- i18n.language
- )
- : '--'}
+ {t('common:support.wallet.subscription.Extra ai points')}
+
+ {activityExpirationTime}
+
-
-
-
- {t('common:support.wallet.subscription.Update extra price')}
-
-
- {selectedPackageIndex !== undefined && extraPointsPackages[selectedPackageIndex]
- ? t('common:extraPointsPrice', {
- price: extraPointsPackages[selectedPackageIndex].price
- })
- : '--'}
-
-
-
-
-
-
-
-
- {t('common:support.wallet.subscription.Update extra ai points tips')}
-
-
-
+ {extraPointsPackages.map((pkg, index) => (
+ 6 ? 1 : 2}
+ px={[3, 4]}
+ borderRadius={['8px', 'sm']}
+ borderWidth={'1px'}
+ borderColor={selectedPackageIndex === index ? '#3E78FF' : 'myGray.200'}
+ bg={selectedPackageIndex === index ? 'primary.25' : 'white'}
+ cursor={'pointer'}
+ _hover={{
+ borderColor: '#3E78FF',
+ bg: 'primary.25'
+ }}
+ onClick={() => setSelectedPackageIndex(index)}
+ transition={'all 0.2s'}
+ position={'relative'}
+ overflow={'hidden'}
+ >
+ {!!pkg.activityBonusPoints && (
+
+ +{formatNumberWithUnit(pkg.activityBonusPoints, i18n.language)}
+
+ )}
+
+ {formatNumberWithUnit(pkg.points, i18n.language)}{' '}
+
+ {t('common:support.wallet.subscription.point')}
+
+
+
+ {t('common:invalid_time') + ' '}
+ {getMonthText(pkg.month)}
+
+
+ ))}
+
- {/* dataset */}
-
-
-
-
- {t('common:support.wallet.subscription.Extra dataset size')}
-
-
- {`¥${extraDatasetPrice}/1000${t('common:support.wallet.subscription.Extra dataset unit')}`}
-
+
- {t('common:support.wallet.subscription.Extra dataset description')}
+ {t('common:support.wallet.subscription.total_points')}
-
-
-
-
-
-
-
-
- {t('common:support.wallet.buy_dataset_capacity')}
+
+ {selectedPackageIndex !== undefined && extraPointsPackages[selectedPackageIndex]
+ ? formatNumberWithUnit(
+ extraPointsPackages[selectedPackageIndex].points +
+ (extraPointsPackages[selectedPackageIndex]?.activityBonusPoints || 0),
+ i18n.language
+ )
+ : '--'}
-
-
-
- {t('common:support.wallet.subscription.Dataset size')}
-
-
-
-
- {`X 1000${t('common:core.dataset.data.group')}`}
-
-
-
-
-
-
- {t('common:invalid_time')}
-
-
+
- setValueDatasetSize('month', val)}
- />
-
-
-
-
-
{t('common:support.wallet.subscription.Update extra price')}
-
- {`¥${(() => {
- const price = calculatePrice(extraDatasetPrice, {
- type: 'dataset',
- size: watchedDatasetSize,
- month: watchedDatasetMonth
- });
- return Number.isNaN(price) ? 0 : price;
- })()}`}
-
+
+ {selectedPackageIndex !== undefined && extraPointsPackages[selectedPackageIndex]
+ ? t('common:extraPointsPrice', {
+ price: extraPointsPackages[selectedPackageIndex].price
+ })
+ : '--'}
+
-
-
-
-
-
- {t('common:support.wallet.subscription.Update extra dataset tips')}
+
+
+
+ {t('common:support.wallet.subscription.Update extra ai points tips')}
-
+
-
-
+ )}
+
+ {showDataset && (
+
+
+
+
+ {t('common:support.wallet.subscription.Extra dataset size')}
+
+
+ {`¥${extraDatasetPrice}/1000${t('common:support.wallet.subscription.Extra dataset unit')}`}
+
+
+ {t('common:support.wallet.subscription.Extra dataset description')}
+
+
+
+
+
+
+
+
+
+ {t('common:support.wallet.buy_dataset_capacity')}
+
+
+
+
+
+ {t('common:support.wallet.subscription.Dataset size')}
+
+
+
+
+ {`X 1000${t('common:core.dataset.data.group')}`}
+
+
+
+
+
+
+ {t('common:invalid_time')}
+
+
+ setValueDatasetSize('month', val)}
+ />
+
+
+
+
+
+ {t('common:support.wallet.subscription.Update extra price')}
+
+
+ {`¥${(() => {
+ const price = calculatePrice(extraDatasetPrice, {
+ type: 'dataset',
+ size: watchedDatasetSize,
+ month: watchedDatasetMonth
+ });
+ return Number.isNaN(price) ? 0 : price;
+ })()}`}
+
+
+
+
+
+
+
+
+
+
+ {t('common:support.wallet.subscription.Update extra dataset tips')}
+
+
+
+
+ )}
+
{!!qrPayData && (
= {
+ label: string;
+ value: T;
+};
+
+/** 购买套餐页 Tab,选中项为圆角 pill 白底样式 */
+const PricePlanTabs = ({
+ list,
+ value,
+ onChange
+}: {
+ list: PricePlanTabItem[];
+ value: T;
+ onChange: (value: T) => void;
+}) => {
+ return (
+
+ {list.map((item) => {
+ const isActive = value === item.value;
+
+ return (
+ {
+ if (!isActive) {
+ onChange(item.value);
+ }
+ }}
+ >
+
+ {item.label}
+
+
+ );
+ })}
+
+ );
+};
+
+export default PricePlanTabs;
diff --git a/projects/app/src/pageComponents/price/Standard.tsx b/projects/app/src/pageComponents/price/Standard.tsx
index 1913cbd7b042..7065800b049e 100644
--- a/projects/app/src/pageComponents/price/Standard.tsx
+++ b/projects/app/src/pageComponents/price/Standard.tsx
@@ -1,7 +1,7 @@
import React, { useEffect, useMemo, useState } from 'react';
import MyIcon from '@fastgpt/web/components/common/Icon';
import { Box, Button, Flex, Grid } from '@chakra-ui/react';
-import { useTranslation } from 'next-i18next';
+import { Trans, useTranslation } from 'next-i18next';
import { StandardSubLevelEnum, SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
import { useSystemStore } from '@/web/common/system/useSystemStore';
import { standardSubLevelMap } from '@fastgpt/global/support/wallet/sub/constants';
@@ -32,12 +32,105 @@ const NEW_PLAN_LEVELS = [
StandardSubLevelEnum.custom
];
+/** 按月/按年切换开关,可在页面 header 区域复用 */
+export const BillingModeSwitch = ({
+ value,
+ onChange
+}: {
+ value: `${SubModeEnum}`;
+ onChange: (mode: `${SubModeEnum}`) => void;
+}) => {
+ const { t } = useTranslation();
+ const isYear = value === SubModeEnum.year;
+
+ return (
+
+
+ {t('common:support.wallet.subscription.mode.Month pay')}
+
+ onChange(isYear ? SubModeEnum.month : SubModeEnum.year)}
+ onKeyDown={(e) => {
+ if (e.key === 'Enter' || e.key === ' ') {
+ e.preventDefault();
+ onChange(isYear ? SubModeEnum.month : SubModeEnum.year);
+ }
+ }}
+ >
+
+
+
+ {t('common:support.wallet.subscription.mode.Year pay')}
+
+
+
+ }}
+ />
+
+
+ );
+};
+
const Standard = ({
standardPlan: myStandardPlan,
- onPaySuccess
+ onPaySuccess,
+ selectSubMode: controlledSubMode,
+ onSelectSubModeChange,
+ hideBillingToggle = false
}: {
standardPlan?: TeamPlanStandardType;
onPaySuccess?: () => void;
+ selectSubMode?: `${SubModeEnum}`;
+ onSelectSubModeChange?: (mode: `${SubModeEnum}`) => void;
+ hideBillingToggle?: boolean;
}) => {
const { t } = useTranslation();
const { userInfo } = useUserStore();
@@ -53,9 +146,11 @@ const Standard = ({
const [packageChange, setPackageChange] = useState();
const { subPlans, feConfigs } = useSystemStore();
- const [selectSubMode, setSelectSubMode] = useState<`${SubModeEnum}`>(
+ const [internalSubMode, setInternalSubMode] = useState<`${SubModeEnum}`>(
isWecomTeam ? SubModeEnum.year : SubModeEnum.month
);
+ const selectSubMode = controlledSubMode ?? internalSubMode;
+ const setSelectSubMode = onSelectSubModeChange ?? setInternalSubMode;
const hasActivityExpiration =
!!subPlans?.activityExpirationTime && selectSubMode === SubModeEnum.year;
@@ -132,7 +227,7 @@ const Standard = ({
})
: [];
}, [
- subPlans?.standard,
+ subPlans,
isWecomTeam,
selectSubMode,
myStandardPlan?.maxTeamMember,
@@ -166,56 +261,17 @@ const Standard = ({
return (
<>
-
- {!isWecomTeam && (
-
-
-
- {t('common:pay_year_tip')}
-
-
- {t('common:support.wallet.subscription.mode.Year')}
-
- ),
- value: SubModeEnum.year
- }
- ]}
- value={selectSubMode}
- onChange={(e) => setSelectSubMode(e as `${SubModeEnum}`)}
- />
-
-
-
+
+ {!hideBillingToggle && !isWecomTeam && (
+
)}
- {/* card */}
-
{standardSubList.map((item) => {
const isCurrentPlan = item.level === myStandardPlan?.currentSubLevel;
@@ -238,21 +294,25 @@ const Standard = ({
{hasActivityExpiration &&
(item.level === StandardSubLevelEnum.basic ||
@@ -600,7 +660,7 @@ const Standard = ({
);
})}
-
+
{!!qrPayData && packageChange && (
void;
-}) => {
- return (
-
- {list.map((item) => (
- onChange(item.value)
- })}
- >
- {item.icon && }
- {item.label}
-
- ))}
-
- );
-};
diff --git a/projects/app/src/pages/price/index.tsx b/projects/app/src/pages/price/index.tsx
index 30f7524c8bb2..e265b97e57d0 100644
--- a/projects/app/src/pages/price/index.tsx
+++ b/projects/app/src/pages/price/index.tsx
@@ -1,10 +1,10 @@
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { serviceSideProps } from '@/web/common/i18n/utils';
-import { Box, Button, Flex, HStack, IconButton, VStack } from '@chakra-ui/react';
+import { Box, Button, Flex, HStack, IconButton } from '@chakra-ui/react';
import { useUserStore } from '@/web/support/user/useUserStore';
import { getTeamPlanStatus } from '@/web/support/user/team/api';
-import StandardPlan from '@/pageComponents/price/Standard';
+import StandardPlan, { BillingModeSwitch } from '@/pageComponents/price/Standard';
import ExtraPlan from '@/pageComponents/price/ExtraPlan';
import PointsCard from '@/pageComponents/price/Points';
import FAQ from '@/pageComponents/price/FAQ';
@@ -14,15 +14,34 @@ import { useSystemStore } from '@/web/common/system/useSystemStore';
import { useRouter } from 'next/router';
import { useRequest } from '@fastgpt/web/hooks/useRequest';
import MyLoading from '@fastgpt/web/components/common/MyLoading';
+import PricePlanTabs from '@/pageComponents/price/PricePlanTabs';
+import { SubModeEnum } from '@fastgpt/global/support/wallet/sub/constants';
+
+type PriceTabType = 'standard' | 'extraPoints' | 'extraDataset';
+
+const EXTRA_PLAN_HASH = 'extra-plan';
+
+/** 根据 URL hash 解析默认 Tab(如账户页「购买额外套餐」跳转 /price#extra-plan) */
+const getTabFromHash = (hash: string): PriceTabType | undefined => {
+ if (hash === EXTRA_PLAN_HASH) {
+ return 'extraPoints';
+ }
+ return undefined;
+};
const PriceBox = () => {
const { initUserInfo } = useUserStore();
const { t } = useTranslation();
- const { feConfigs } = useSystemStore();
+ const { subPlans } = useSystemStore();
const router = useRouter();
const backButtonRef = useRef(null);
const [isButtonInView, setIsButtonInView] = useState(true);
+ const [userActiveTab, setUserActiveTab] = useState(() => {
+ if (typeof window === 'undefined') return 'standard';
+ return getTabFromHash(window.location.hash.slice(1)) ?? 'standard';
+ });
+ const [userSubMode, setUserSubMode] = useState<`${SubModeEnum}`>(SubModeEnum.month);
const { data: userInfo, loading: userInfoLoading } = useRequest(initUserInfo, {
manual: false
@@ -33,11 +52,28 @@ const PriceBox = () => {
refreshDeps: [userInfo]
});
+ const hashTab = useMemo(() => {
+ if (!router.isReady) return undefined;
+ return getTabFromHash(router.asPath.split('#')[1] ?? '');
+ }, [router.isReady, router.asPath]);
+
+ const activeTab = hashTab ?? userActiveTab;
+ const selectSubMode = subPlans?.activityExpirationTime ? SubModeEnum.year : userSubMode;
+
+ const handleTabChange = useCallback(
+ (value: PriceTabType) => {
+ setUserActiveTab(value);
+ if (router.asPath.includes('#')) {
+ void router.replace('/price', undefined, { shallow: true });
+ }
+ },
+ [router]
+ );
+
// TODO: 封装成一个 hook 来判断滚动态
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
- // 当按钮在视图内时,隐藏浮动按钮;当按钮不在视图内时,显示浮动按钮
setIsButtonInView(entry.isIntersecting);
},
{
@@ -60,11 +96,9 @@ const PriceBox = () => {
});
const handleBack = useCallback(() => {
- // Check if there is history to go back to
if (window.history.length > 1) {
router.back();
} else {
- // No history, navigate to home page
router.push('/dashboard/agent');
}
}, [router]);
@@ -76,10 +110,26 @@ const PriceBox = () => {
}, [router]);
const isWecomTeam = useMemo(() => !!userInfo?.team?.isWecomTeam, [userInfo?.team?.isWecomTeam]);
-
- // Show loading state while fetching user info to prevent flash of incorrect content
const isLoading = userInfoLoading || teamSubPlanLoading;
+ const tabList = useMemo(
+ () => [
+ {
+ label: t('common:support.wallet.subscription.Basic plan tab'),
+ value: 'standard' as const
+ },
+ {
+ label: t('common:support.wallet.subscription.Extra points tab'),
+ value: 'extraPoints' as const
+ },
+ {
+ label: t('common:support.wallet.subscription.Extra dataset tab'),
+ value: 'extraDataset' as const
+ }
+ ],
+ [t]
+ );
+
return (
<>
{isLoading ? (
@@ -90,81 +140,114 @@ const PriceBox = () => {
flexDir={'column'}
overflow={'overlay'}
w={'100%'}
- px={['20px', '5vw']}
- py={['30px', '80px']}
bg={`linear-gradient(to right, #F8F8FD00, #F7F7FF),url(/imgs/priceBg.svg)`}
backgroundSize={'cover'}
backgroundRepeat={'no-repeat'}
>
- {teamSubPlan?.standard?.teamId && (
- }
- onClick={handleBack}
- alignSelf={'flex-start'}
- mt={-8}
- >
- {t('common:back')}
-
- )}
- {(!isButtonInView || !teamSubPlan?.standard?.teamId) && (
- }
- onClick={handleBack}
- />
- )}
-
- {/* standard sub */}
-
-
- {t('common:support.wallet.subscription.Sub plan')}
-
-
- {isWecomTeam
- ? t('common:support.wallet.subscription.Sub plan tip wecom')
- : t('common:support.wallet.subscription.Sub plan tip', {
- title: feConfigs?.systemTitle
- })}
-
-
-
-
-
- {t('user:bill.standard_valid_tip')}
+
+ {teamSubPlan?.standard?.teamId && (
+ }
+ onClick={handleBack}
+ alignSelf={'flex-start'}
+ mb={6}
+ >
+ {t('common:back')}
+
+ )}
+ {(!isButtonInView || !teamSubPlan?.standard?.teamId) && (
+ }
+ onClick={handleBack}
+ />
+ )}
+
+
+
+ {t('common:support.wallet.subscription.Purchase plan')}
+
+
+
+ handleTabChange(value as PriceTabType)}
+ />
-
-
-
- {/* extra plan */}
-
-
-
- {t('common:support.wallet.subscription.Extra plan tip')}
-
-
-
-
- {/* points */}
-
-
- {/* question */}
-
+
+ {activeTab === 'standard' && !isWecomTeam && (
+
+
+
+ )}
+
+ {activeTab !== 'standard' && (
+
+ )}
+
+
+ {activeTab === 'standard' && (
+
+
+
+
+
+ {t('user:bill.standard_valid_tip')}
+
+
+
+ )}
+
+ {activeTab !== 'standard' && (
+
+
+
+ )}
+
+
+ {/* AI 积分计算标准、FAQ:保持原页面布局,不受 tab 区域 maxW / padding 影响 */}
+
+
+
+
)}
>