feat: enhance wallet billing features (#5293)

* feat: enhance wallet billing features with new dataset and points options

* chore: removed local state for dataset month and replaced it with form state management

* chore: remove redundant state
This commit is contained in:
酒川户
2025-07-23 18:22:28 +08:00
committed by GitHub
parent e008b21954
commit 662c790fe4
10 changed files with 394 additions and 157 deletions

View File

@@ -16,6 +16,7 @@ export type CreateStandPlanBill = {
type CreateExtractPointsBill = {
type: BillTypeEnum.extraPoints;
extraPoints: number;
month: number;
};
type CreateExtractDatasetBill = {
type: BillTypeEnum.extraDatasetSub;

View File

@@ -0,0 +1,37 @@
import type { PriceOption } from './type';
// 根据积分获取月份
export const getMonthByPoints = (points: number) => {
if (points >= 200) return 12;
if (points >= 100) return 6;
if (points >= 50) return 3;
return 1;
};
// 根据月份获取积分下限
export const getMinPointsByMonth = (month: number): number => {
switch (month) {
case 12:
return 200;
case 6:
return 100;
case 3:
return 50;
case 1:
return 1;
default:
return 1;
}
};
// 计算额外资源包的所需付款价格
export const calculatePrice = (unitPrice: number, option: PriceOption) => {
switch (option.type) {
case 'points':
return unitPrice * option.points * 1;
case 'dataset':
return unitPrice * option.size * option.month;
default:
throw new Error('Invalid price option type');
}
};

View File

@@ -50,3 +50,16 @@ export type InvoiceSchemaType = {
finishTime?: Date;
file?: Buffer;
} & InvoiceType;
export type AIPointsPriceOption = {
type: 'points';
points: number;
};
export type DatasetPriceOption = {
type: 'dataset';
size: number;
month: number;
};
export type PriceOption = AIPointsPriceOption | DatasetPriceOption;

View File

@@ -74,6 +74,7 @@ export const menuItemStyles: MenuItemProps = {
const MySelect = <T = any,>(
{
bg = '#fff',
placeholder,
value,
valueLabel,
@@ -223,6 +224,7 @@ const MySelect = <T = any,>(
_active={{
transform: 'none'
}}
bg={bg ? (isOpen ? '#fff' : bg) : '#fff'}
color={isOpen ? 'primary.700' : 'myGray.700'}
borderColor={isInvalid ? 'red.500' : isOpen ? 'primary.300' : 'myGray.200'}
boxShadow={
@@ -232,17 +234,7 @@ const MySelect = <T = any,>(
: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)'
: 'none'
}
_hover={
isInvalid
? {
borderColor: 'red.400',
boxShadow: '0px 0px 0px 2.4px rgba(255, 0, 0, 0.15)'
}
: {
borderColor: 'primary.300',
boxShadow: '0px 0px 0px 2.4px rgba(51, 112, 255, 0.15)'
}
}
_hover={isInvalid ? { borderColor: 'red.400' } : { borderColor: 'primary.300' }}
{...props}
>
<Flex alignItems={'center'} justifyContent="space-between" w="100%">

View File

@@ -469,7 +469,7 @@
"core.dataset.data.Search data placeholder": "Search Related Data",
"core.dataset.data.Too Long": "Total Length Exceeded",
"core.dataset.data.Updated": "Updated",
"core.dataset.data.group": "Group",
"core.dataset.data.group": " Groups",
"core.dataset.data.unit": "Items",
"core.dataset.embedding model tip": "The index model can convert natural language into vectors for semantic search.\nNote that different index models cannot be used together. Once an index model is selected, it cannot be changed.",
"core.dataset.error.Data not found": "Data Not Found or Deleted",
@@ -1119,6 +1119,8 @@
"support.wallet.bill_tag.default_header": "Default Header",
"support.wallet.bill_tag.invoice": "Invoice Records",
"support.wallet.billable_invoice": "Billable Invoice",
"support.wallet.buy_ai_points": "Buy AI points",
"support.wallet.buy_dataset_capacity": "Buy Knowledge Base Index",
"support.wallet.buy_resource": "Buy Resource Pack",
"support.wallet.has_invoice": "Invoiced",
"support.wallet.invoice_amount": "Invoice Amount",
@@ -1142,20 +1144,33 @@
"support.wallet.subscription.AI points usage tip": "Each time the AI model is called, a certain amount of AI points will be consumed. For specific calculation standards, please refer to the 'Pricing' above.",
"support.wallet.subscription.Ai points": "AI Points Calculation Standards",
"support.wallet.subscription.Current plan": "Current Package",
"support.wallet.subscription.Extra ai points": "AI points",
"support.wallet.subscription.Dataset size": "Knowledge Base Index",
"support.wallet.subscription.Extra ai points": "AI Points",
"support.wallet.subscription.Extra ai points description": "The purchase amount of points is intelligently linked to the validity period. The more you buy, the longer you use it.",
"support.wallet.subscription.Extra dataset description": "Supports extending the validity period for the knowledge base index based on actual needs",
"support.wallet.subscription.Extra dataset size": "Extra Dataset Capacity",
"support.wallet.subscription.Extra dataset unit": " Groups/1 Month",
"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.Month amount": "Months",
"support.wallet.subscription.Next plan": "Future Package",
"support.wallet.subscription.Points amount": "AI Points",
"support.wallet.subscription.Stand plan level": "Subscription Package",
"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.Team plan and usage": "Package and Usage",
"support.wallet.subscription.Training weight": "Training Priority: {{weight}}",
"support.wallet.subscription.Update extra ai points": "Extra AI Points",
"support.wallet.subscription.Update extra ai points tips": "Purchase points will take effect immediately and will automatically expire after expiration.",
"support.wallet.subscription.Update extra dataset size": "Storage",
"support.wallet.subscription.Update extra dataset tips": "After the knowledge base index expires, the existing data is still retained and the data cannot be added or modified.",
"support.wallet.subscription.Update extra expire": "Validity period",
"support.wallet.subscription.Update extra expire 1 month": "1 Month",
"support.wallet.subscription.Update extra expire 12 months": "12 Months",
"support.wallet.subscription.Update extra expire 3 months": "3 Months",
"support.wallet.subscription.Update extra expire 6 months": "6 Months",
"support.wallet.subscription.Update extra price": "Price",
"support.wallet.subscription.Upgrade plan": "Upgrade Package",
"support.wallet.subscription.ai_model": "AI Language Model",
"support.wallet.subscription.function.History store": "{{amount}} Days of Chat History Retention",
@@ -1168,7 +1183,7 @@
"support.wallet.subscription.mode.Period": "Subscription Period",
"support.wallet.subscription.mode.Year": "Year",
"support.wallet.subscription.mode.Year sale": "Two Months Free",
"support.wallet.subscription.point": "Points",
"support.wallet.subscription.point": " Points",
"support.wallet.subscription.standardSubLevel.custom": "Custom",
"support.wallet.subscription.standardSubLevel.enterprise": "Enterprise",
"support.wallet.subscription.standardSubLevel.enterprise_desc": "Suitable for small and medium-sized enterprises to build Dataset applications in production environments",

View File

@@ -1143,6 +1143,7 @@
"support.wallet.subscription.Ai points": "AI 积分计算标准",
"support.wallet.subscription.Current plan": "当前套餐",
"support.wallet.subscription.Extra ai points": "额外 AI 积分",
"support.wallet.subscription.Extra ai points description": "积分购买量与有效期智能联动, 买的越多用的越久",
"support.wallet.subscription.Extra dataset size": "额外知识库容量",
"support.wallet.subscription.Extra plan": "额外资源包",
"support.wallet.subscription.Extra plan tip": "标准套餐不够时,您可以购买额外资源包继续使用",
@@ -1156,6 +1157,20 @@
"support.wallet.subscription.Training weight": "训练优先级:{{weight}}",
"support.wallet.subscription.Update extra ai points": "额外 AI 积分",
"support.wallet.subscription.Update extra dataset size": "额外存储量",
"support.wallet.subscription.Update extra expire 1 month": "1个月",
"support.wallet.subscription.Update extra expire 12 months": "12个月",
"support.wallet.subscription.Update extra expire 3 months": "3个月",
"support.wallet.subscription.Update extra expire 6 months": "6个月",
"support.wallet.buy_ai_points": "购买 AI 积分",
"support.wallet.subscription.Update extra expire": "有效期",
"support.wallet.subscription.Update extra price": "价格",
"support.wallet.subscription.Update extra dataset tips": "知识库索引量到期后,仍保留已有数据,无法增改数据",
"support.wallet.subscription.Dataset size": "知识库索引量",
"support.wallet.buy_dataset_capacity": "购买知识库索引量",
"support.wallet.subscription.Extra dataset description": "支持根据实际需求为知识库索引量延长有效期",
"support.wallet.subscription.Extra dataset unit": "组/1个月",
"support.wallet.subscription.Update extra ai points tips": "购买积分即刻生效,过期后将自动失效",
"support.wallet.subscription.Points amount": "积分量",
"support.wallet.subscription.Upgrade plan": "升级套餐",
"support.wallet.subscription.ai_model": "AI语言模型",
"support.wallet.subscription.eval_items_count": "单次评测数据条数: {{count}} 条",

View File

@@ -1119,6 +1119,8 @@
"support.wallet.bill_tag.default_header": "預設抬頭",
"support.wallet.bill_tag.invoice": "發票紀錄",
"support.wallet.billable_invoice": "可開立發票的帳單",
"support.wallet.buy_ai_points": "購買 AI 積分",
"support.wallet.buy_dataset_capacity": "購買知識庫索引量",
"support.wallet.buy_resource": "購買資源包",
"support.wallet.has_invoice": "已開立發票",
"support.wallet.invoice_amount": "發票金額",
@@ -1142,20 +1144,33 @@
"support.wallet.subscription.AI points usage tip": "每次呼叫 AI 模型時,都會消耗一定的 AI 點數。具體的計算標準可參考上方的「計費標準」",
"support.wallet.subscription.Ai points": "AI 點數計算標準",
"support.wallet.subscription.Current plan": "目前方案",
"support.wallet.subscription.Dataset size": "知識庫索引量",
"support.wallet.subscription.Extra ai points": "額外 AI 點數",
"support.wallet.subscription.Extra ai points description": "積分購買量與有效期智能聯動, 買的越多用的越久",
"support.wallet.subscription.Extra dataset description": "支持根據實際需求為知識庫索引量延長有效期",
"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.FAQ": "常見問題",
"support.wallet.subscription.Month amount": "月數",
"support.wallet.subscription.Next plan": "未來方案",
"support.wallet.subscription.Points amount": "積分量",
"support.wallet.subscription.Stand plan level": "訂閱方案",
"support.wallet.subscription.Sub plan": "訂閱方案",
"support.wallet.subscription.Sub plan tip": "免費使用【{{title}}】或升級更進階的方案",
"support.wallet.subscription.Team plan and usage": "方案與使用量",
"support.wallet.subscription.Training weight": "訓練優先權:{{weight}}",
"support.wallet.subscription.Update extra ai points": "額外 AI 點數",
"support.wallet.subscription.Update extra ai points tips": "購買積分即刻生效,過期後將自動失效",
"support.wallet.subscription.Update extra dataset size": "額外儲存空間",
"support.wallet.subscription.Update extra dataset tips": "知識庫索引量到期後,仍保留已有數據,無法增改數據",
"support.wallet.subscription.Update extra expire": "有效期",
"support.wallet.subscription.Update extra expire 1 month": "1個月",
"support.wallet.subscription.Update extra expire 12 months": "12個月",
"support.wallet.subscription.Update extra expire 3 months": "3個月",
"support.wallet.subscription.Update extra expire 6 months": "6個月",
"support.wallet.subscription.Update extra price": "價格",
"support.wallet.subscription.Upgrade plan": "升級方案",
"support.wallet.subscription.ai_model": "AI 語言模型",
"support.wallet.subscription.function.History store": "{{amount}} 天對話紀錄保留",

View File

@@ -244,14 +244,8 @@ export const LoginContainer = ({
<Box position="relative" w="full" h="full">
{/* main content area */}
<Box w={['100%', '380px']} flex={'1 0 0'}>
{pageType && DynamicComponent ? (
DynamicComponent
) : (
<Center w={'full'} h={'full'} position={'relative'}>
<Loading fixed={false} />
</Center>
)}
<Box w={['100%', '380px']} minH={['100vh', '600px']} flex={'1 0 0'}>
{pageType && DynamicComponent ? DynamicComponent : <Loading fixed={false} />}
</Box>
{/* custom content */}

View File

@@ -1,4 +1,4 @@
import { Box, Flex, Grid, Button, VStack } from '@chakra-ui/react';
import { Box, Flex, Grid, Button, VStack, HStack } from '@chakra-ui/react';
import { useTranslation } from 'next-i18next';
import React, { useState } from 'react';
import { useSystemStore } from '@/web/common/system/useSystemStore';
@@ -10,6 +10,12 @@ import { BillTypeEnum } from '@fastgpt/global/support/wallet/bill/constants';
import QRCodePayModal, { type QRPayProps } from '@/components/support/wallet/QRCodePayModal';
import MyNumberInput from '@fastgpt/web/components/common/Input/NumberInput';
import { useRequest2 } from '@fastgpt/web/hooks/useRequest';
import MySelect from '@fastgpt/web/components/common/MySelect';
import {
getMonthByPoints,
getMinPointsByMonth,
calculatePrice
} from '@fastgpt/global/support/wallet/bill/tools';
const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
const { t } = useTranslation();
@@ -17,14 +23,30 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
const { subPlans } = useSystemStore();
const [qrPayData, setQRPayData] = useState<QRPayProps>();
// extra dataset
const expireSelectorOptions: { label: string; value: number }[] = [
{ label: t('common:support.wallet.subscription.Update extra expire 1 month'), value: 1 },
{ label: t('common:support.wallet.subscription.Update extra expire 3 months'), value: 3 },
{ label: t('common:support.wallet.subscription.Update extra expire 6 months'), value: 6 },
{ label: t('common:support.wallet.subscription.Update extra expire 12 months'), value: 12 }
];
// 额外的知识库索引量
const extraDatasetPrice = subPlans?.extraDatasetSize?.price || 0;
const { register: registerDatasetSize, handleSubmit: handleSubmitDatasetSize } = useForm({
const {
watch: watchDatasetSize,
register: registerDatasetSize,
handleSubmit: handleSubmitDatasetSize,
setValue: setValueDatasetSize
} = useForm({
defaultValues: {
datasetSize: 0,
datasetSize: 1,
month: 1
}
});
const watchedDatasetSize = watchDatasetSize('datasetSize');
const watchedDatasetMonth = watchDatasetSize('month');
const { runAsync: onclickBuyDatasetSize, loading: isLoadingBuyDatasetSize } = useRequest2(
async ({ datasetSize, month }: { datasetSize: number; month: number }) => {
datasetSize = Math.ceil(datasetSize);
@@ -56,18 +78,27 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
// extra ai points
const extraPointsPrice = subPlans?.extraPoints?.price || 0;
const { register: registerExtraPoints, handleSubmit: handleSubmitExtraPoints } = useForm({
const {
watch: watchExtraPoints,
setValue: setValueExtraPoints,
getValues: getValuesExtraPoints
} = useForm({
defaultValues: {
points: 0,
points: 1,
month: 1
}
});
const { runAsync: onclickBuyExtraPoints, loading: isLoadingBuyExtraPoints } = useRequest2(
async ({ points }: { points: number }) => {
points = Math.ceil(points);
const month = 1;
const payAmount = points * month * extraPointsPrice;
// 监听积分和月份变化
const watchedPoints = watchExtraPoints('points');
const watchedMonth = watchExtraPoints('month');
const { runAsync: onclickBuyExtraPoints, loading: isLoadingBuyExtraPoints } = useRequest2(
async ({ points, month }: { points: number; month: number }) => {
points = Math.ceil(points);
month = Math.ceil(month);
const payAmount = points * 1 * extraPointsPrice;
if (payAmount === 0) {
return toast({
@@ -78,6 +109,7 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
const res = await postCreatePayBill({
type: BillTypeEnum.extraPoints,
month,
extraPoints: points
});
@@ -95,89 +127,9 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
return (
<VStack>
<Grid gridTemplateColumns={['1fr', '1fr 1fr']} gap={5} w={['100%', 'auto']}>
<Box
bg={'rgba(255, 255, 255, 0.90)'}
px={'32px'}
py={'24px'}
borderRadius={'2xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
boxShadow={'1.5'}
w={['100%', '500px']}
>
<Flex borderBottomWidth={'1px'} borderBottomColor={'myGray.200'}>
<Box flex={'1 0 0'}>
<Box fontSize={'lg'} color={'primary.700'}>
{t('common:support.wallet.subscription.Extra dataset size')}
</Box>
<Box mt={3} fontSize={['28px', '32px']} fontWeight={'bold'} color={'black'}>
{`${extraDatasetPrice}/1000` + t('common:core.dataset.data.group')}
<Box ml={1} as={'span'} fontSize={'md'} color={'myGray.500'} fontWeight={'normal'}>
/{t('common:month')}
</Box>
</Box>
</Box>
<MyIcon
display={['none', 'block']}
mt={'-30px'}
transform={'translateX(20px)'}
name={'support/bill/extraDatasetsize'}
fill={'none'}
/>
</Flex>
<Box h={'120px'} w={'100%'}>
<Flex mt={4} color={'myGray.900'}>
<MyIcon mr={2} name={'support/bill/shoppingCart'} w={'16px'} color={'primary.600'} />
{t('common:support.wallet.buy_resource')}
</Flex>
<Flex mt={4} alignItems={'center'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'}>
{t('common:support.wallet.subscription.Month amount')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<MyNumberInput
name="month"
register={registerDatasetSize}
min={1}
max={12}
size={'sm'}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.600'} fontSize={'xs'}>
{t('common:month')}
</Box>
</Flex>
</Flex>
<Flex mt={4} alignItems={'center'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'}>
{t('common:support.wallet.subscription.Update extra dataset size')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<MyNumberInput
name="datasetSize"
register={registerDatasetSize}
min={0}
max={10000}
size={'sm'}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.600'} fontSize={'xs'}>
000{t('common:core.dataset.data.unit')}
</Box>
</Flex>
</Flex>
</Box>
<Button
mt={6}
w={'100%'}
variant={'primaryGhost'}
isLoading={isLoadingBuyDatasetSize}
onClick={handleSubmitDatasetSize(onclickBuyDatasetSize)}
color={'primary.700'}
>
{t('common:support.wallet.Buy')}
</Button>
</Box>
{/* points */}
<Box
<Flex
flexDir="column"
bg={'rgba(255, 255, 255, 0.90)'}
w={['100%', '500px']}
px={'32px'}
@@ -186,19 +138,20 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
borderWidth={'1px'}
borderColor={'myGray.150'}
boxShadow={'1.5'}
gap={4}
>
<Flex borderBottomWidth={'1px'} borderBottomColor={'myGray.200'}>
<Box flex={'1 0 0'}>
<Box fontSize={'lg'} color={'primary.700'}>
<Flex borderBottomWidth={'1px'} borderBottomColor={'myGray.200'} pb={1}>
<Flex flexDir="column" gap={3} flex={'1 0 0'}>
<Box fontSize={'lg'} fontWeight={'500'} color={'primary.700'}>
{t('common:support.wallet.subscription.Extra ai points')}
</Box>
<Box mt={3} fontSize={['28px', '32px']} fontWeight={'bold'} color={'black'}>
<Box fontSize={['28px', '32px']} fontWeight={'bold'} color={'black'}>
{`${extraPointsPrice}/1000` + t('common:support.wallet.subscription.point')}
<Box ml={1} as={'span'} fontSize={'md'} color={'myGray.500'} fontWeight={'normal'}>
/{t('common:month')}
</Box>
</Box>
</Box>
<Box mt="auto" fontSize={'xs'} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Extra ai points description')}
</Box>
</Flex>
<MyIcon
display={['none', 'block']}
mt={'-30px'}
@@ -207,55 +160,257 @@ const ExtraPlan = ({ onPaySuccess }: { onPaySuccess?: () => void }) => {
fill={'none'}
/>
</Flex>
<Box h={'120px'} w={'100%'}>
<Flex mt={4} color={'myGray.900'}>
<MyIcon mr={2} name={'support/bill/shoppingCart'} w={'16px'} color={'primary.600'} />
{t('common:support.wallet.buy_resource')}
<Flex flexDir="column" gap={4} h={'180px'} w={'100%'}>
<Flex color={'myGray.900'}>
<MyIcon
mr={2}
name={'support/bill/shoppingCart'}
fontWeight={'500'}
w={'16px'}
color={'primary.600'}
/>
{t('common:support.wallet.buy_ai_points')}
</Flex>
<Flex mt={4} alignItems={'center'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'}>
{t('common:support.wallet.subscription.Month amount')}
</Box>
<Flex alignItems={'center'} mt={1} w={'180px'} position={'relative'}>
<Box>1</Box>
<Box color={'myGray.600'}>{t('common:month')}</Box>
</Flex>
</Flex>
<Flex mt={4} alignItems={'center'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'}>
{t('common:support.wallet.subscription.Update extra ai points')}
<Flex alignItems={'center'} fontSize={'sm'} h="36px">
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Points amount')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
color={'myGray.500'}
>
<MyNumberInput
name="points"
register={registerExtraPoints}
min={0}
value={watchedPoints}
max={10000}
min={0}
size={'sm'}
onChange={(val) => {
// 过滤掉NaN和无效输入
if (val === ('' as unknown as number) || val === null || val === undefined) {
setValueExtraPoints('points', undefined as unknown as number);
} else if (!isNaN(val) && val >= 0) {
setValueExtraPoints('points', val as unknown as number);
// 当用户输入积分时,自动更新月份
const expectedMonth = getMonthByPoints(val);
if (expectedMonth !== watchedMonth) {
setValueExtraPoints('month', expectedMonth);
}
}
}}
/>
<Box position={'absolute'} right={'30px'} color={'myGray.500'} fontSize={'xs'}>
{'000' + t('common:support.wallet.subscription.point')}
<Box flexShrink={0} color={'myGray.600'}>
&nbsp;{`X 1000${t('common:support.wallet.subscription.point')}`}
</Box>
</Flex>
</Flex>
<Flex alignItems={'center'} fontSize={'sm'} h="36px">
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra expire')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
>
<MySelect
bg={'myGray.50'}
value={watchedMonth}
size={'sm'}
list={expireSelectorOptions}
onChange={(val) => {
setValueExtraPoints('month', val);
// 当用户选择月份时,设置积分为该月份的最小值
const minPoints = getMinPointsByMonth(val);
setValueExtraPoints('points', minPoints);
}}
/>
</Flex>
</Flex>
<Flex alignItems={'end'} fontSize={'sm'} h="36px">
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra price')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
fontWeight={500}
fontSize={'20px'}
>
{`${(() => {
const price = calculatePrice(extraPointsPrice, {
type: 'points',
points: watchedPoints
});
return Number.isNaN(price) ? 0 : price;
})()}`}
</Flex>
</Flex>
</Flex>
<Box mt={'auto'}>
<Button
w={'100%'}
h={'44px'}
variant={'primaryGhost'}
isLoading={isLoadingBuyExtraPoints}
onClick={() => {
const values = getValuesExtraPoints();
const points = values.points || 1; // 如果为空默认为1
const month = values.month || 1;
onclickBuyExtraPoints({ points, month });
}}
color={'primary.700'}
>
{t('common:support.wallet.Buy')}
</Button>
<HStack color={'blue.700'} mt={4}>
<MyIcon name={'infoRounded'} w={'1rem'} />
<Box fontSize={'sm'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra ai points tips')}
</Box>
</HStack>
</Box>
<Button
mt={6}
w={'100%'}
variant={'primaryGhost'}
isLoading={isLoadingBuyExtraPoints}
onClick={handleSubmitExtraPoints(onclickBuyExtraPoints)}
color={'primary.700'}
>
{t('common:support.wallet.Buy')}
</Button>
</Box>
</Flex>
{/* dataset */}
<Flex
flexDir="column"
bg={'rgba(255, 255, 255, 0.90)'}
px={'32px'}
py={'24px'}
borderRadius={'2xl'}
borderWidth={'1px'}
borderColor={'myGray.150'}
boxShadow={'1.5'}
w={['100%', '500px']}
gap={4}
>
<Flex borderBottomWidth={'1px'} borderBottomColor={'myGray.200'} pb={1}>
<Flex flexDir="column" gap={3} flex={'1 0 0'}>
<Box fontSize={'lg'} fontWeight={'500'} color={'primary.700'}>
{t('common:support.wallet.subscription.Extra dataset size')}
</Box>
<Box fontSize={['28px', '32px']} fontWeight={'bold'} color={'black'}>
{`${extraDatasetPrice}/1000${t('common:support.wallet.subscription.Extra dataset unit')}`}
</Box>
<Box mt="auto" fontSize={'xs'} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Extra dataset description')}
</Box>
</Flex>
<MyIcon
display={['none', 'block']}
mt={'-30px'}
transform={'translateX(20px)'}
name={'support/bill/extraDatasetsize'}
fill={'none'}
/>
</Flex>
<Flex flexDir="column" gap={4} h={'180px'} w={'100%'}>
<Flex color={'myGray.900'}>
<MyIcon
mr={2}
name={'support/bill/shoppingCart'}
fontWeight={'500'}
w={'16px'}
color={'primary.600'}
/>
{t('common:support.wallet.buy_dataset_capacity')}
</Flex>
<Flex alignItems={'center'} fontSize={'sm'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Dataset size')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
>
<MyNumberInput
name="datasetSize"
register={registerDatasetSize}
defaultValue={1}
max={10000}
min={0}
size={'sm'}
/>
<Box flexShrink={0} color={'myGray.600'}>
&nbsp;{`X 1000${t('common:core.dataset.data.group')}`}
</Box>
</Flex>
</Flex>
<Flex alignItems={'center'} fontSize={'sm'}>
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra expire')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
>
<MySelect
bg={'myGray.50'}
value={watchedDatasetMonth}
size={'sm'}
list={expireSelectorOptions}
onChange={(val) => setValueDatasetSize('month', val)}
/>
</Flex>
</Flex>
<Flex alignItems={'end'} fontSize={'sm'} h="36px">
<Box flex={['0 0 100px', '1 0 0']} color={'myGray.600'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra price')}
</Box>
<Flex
justifyContent={'end'}
alignItems={'center'}
mt={1}
w={'180px'}
position={'relative'}
fontWeight={500}
fontSize={'20px'}
>
{`${(() => {
const price = calculatePrice(extraDatasetPrice, {
type: 'dataset',
size: watchedDatasetSize,
month: watchedDatasetMonth
});
return Number.isNaN(price) ? 0 : price;
})()}`}
</Flex>
</Flex>
</Flex>
<Box mt={'auto'}>
<Button
w={'100%'}
h={'44px'}
variant={'primaryGhost'}
isLoading={isLoadingBuyDatasetSize}
onClick={handleSubmitDatasetSize(onclickBuyDatasetSize)}
color={'primary.700'}
>
{t('common:support.wallet.Buy')}
</Button>
<HStack color={'blue.700'} mt={4}>
<MyIcon name={'infoRounded'} w={'1rem'} />
<Box fontSize={'sm'} fontWeight={'500'}>
{t('common:support.wallet.subscription.Update extra dataset tips')}
</Box>
</HStack>
</Box>
</Flex>
</Grid>
{!!qrPayData && <QRCodePayModal onSuccess={onPaySuccess} {...qrPayData} />}

View File

@@ -48,7 +48,7 @@ const PriceBox = () => {
<Box fontWeight={'600'} color={'myGray.900'} fontSize={['24px', '36px']}>
{t('common:support.wallet.subscription.Sub plan')}
</Box>
<Box mt={8} mb={10} fontWeight={'500'} color={'myGray.600'} fontSize={'md'}>
<Box fontWeight={'500'} color={'myGray.600'} fontSize={'md'}>
{t('common:support.wallet.subscription.Sub plan tip', {
title: feConfigs?.systemTitle
})}