196 lines
5.9 KiB
TypeScript
196 lines
5.9 KiB
TypeScript
import { useState, useEffect, useMemo } from 'react';
|
||
import { App as AntApp } from 'antd';
|
||
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
|
||
import { MembershipAPI, MembershipInfo } from '../../api/membership';
|
||
|
||
export interface PricingTier {
|
||
id: string;
|
||
name: string;
|
||
price: string;
|
||
yearlyPrice?: string;
|
||
yearlyMonthlyPrice?: string;
|
||
unit: string;
|
||
description: string;
|
||
features: string[];
|
||
points?: string;
|
||
models?: string;
|
||
bonus?: string;
|
||
tag?: string;
|
||
buttonText: string;
|
||
type: 'personal' | 'enterprise';
|
||
}
|
||
|
||
export const PERSONAL_TIERS: PricingTier[] = [
|
||
{
|
||
id: 'trial',
|
||
name: 'Trial',
|
||
price: '0',
|
||
unit: '人民币/月',
|
||
description: '适合首次探索和轻量使用',
|
||
features: ['首次探索和轻量任务。', '试用期后,可以升级至更高级版本。'],
|
||
points: '每日登录积分 10',
|
||
bonus: 'Aura Work: 7天试用积分',
|
||
tag: '体验',
|
||
buttonText: '当前订阅',
|
||
type: 'personal',
|
||
},
|
||
{
|
||
id: 'pro',
|
||
name: 'Pro',
|
||
price: '139',
|
||
yearlyPrice: '1390',
|
||
yearlyMonthlyPrice: '116',
|
||
unit: '人民币/月',
|
||
description: '每周工作与日常执行',
|
||
features: ['适合每周轻量调研、数据分析和任务跟进。', '为稳定的每周产出而设,无需顾虑额外消耗', '限时优惠:订阅用户可享受更多专属权益。'],
|
||
points: '每日登录积分 30',
|
||
models: '高质量模型 50次 / 3小时',
|
||
bonus: '会员积分 4000 / 月',
|
||
tag: '热门',
|
||
buttonText: '开始',
|
||
type: 'personal',
|
||
},
|
||
{
|
||
id: 'ultra',
|
||
name: 'Ultra',
|
||
price: '1399',
|
||
yearlyPrice: '13990',
|
||
yearlyMonthlyPrice: '1116',
|
||
unit: '人民币/月',
|
||
description: '超大项目与更高配置',
|
||
features: ['适合高强度任务与重度使用场景', '面向需要更高积分与更大灵活性的资源用户', '限时优惠:订阅用户可享受更多专属权益。', '个人套餐顶配版,包含全部能力'],
|
||
points: '每日登录积分 100',
|
||
models: '无限制使用高质量模型',
|
||
bonus: '会员积分 40000 / 月',
|
||
tag: '旗舰',
|
||
buttonText: '开始',
|
||
type: 'personal',
|
||
},
|
||
];
|
||
|
||
export const ENTERPRISE_TIERS: PricingTier[] = [
|
||
{
|
||
id: 'ent_basic',
|
||
name: '企业入门版',
|
||
price: '20000',
|
||
unit: '人民币/年',
|
||
description: '适合快速起步的小团队',
|
||
features: ['所有子账号共享企业积分池', '全员共享插件', '企业发票 (增值税普票)', '用量报告与成员消耗排行'],
|
||
points: '企业积分池 35000 / 月',
|
||
models: '高质量模型配额 100次 / 3小时',
|
||
bonus: '子账号上限 5',
|
||
tag: '基础',
|
||
buttonText: '立即开通',
|
||
type: 'enterprise',
|
||
},
|
||
{
|
||
id: 'ent_standard',
|
||
name: '企业标准版',
|
||
price: '40000',
|
||
unit: '人民币/年',
|
||
description: '适合日常协作提效',
|
||
features: ['所有子账号共享企业积分池', '全员共享插件', '企业发票 (增值税普票)', '用量报告与成员消耗排行', '成员角色管理'],
|
||
points: '企业积分池 80000 / 月',
|
||
models: '高质量模型配额 100次 / 3小时',
|
||
bonus: '子账号上限 15',
|
||
tag: '热门',
|
||
buttonText: '立即开通',
|
||
type: 'enterprise',
|
||
},
|
||
{
|
||
id: 'custom',
|
||
name: '按需定制',
|
||
price: '面议',
|
||
unit: '',
|
||
description: '适合大型团队 / 行业方案',
|
||
features: ['独立部署 / 专属网络环境', '统一登录 / 操作记录可追溯', '行业专属插件与技能', '服务保障与 7×24 专属支持', '专属折扣'],
|
||
points: '企业积分池 面议',
|
||
models: '高质量模型配额 不限量',
|
||
bonus: '子账号上限 不限量',
|
||
tag: '专享',
|
||
buttonText: '联系我们',
|
||
type: 'enterprise',
|
||
},
|
||
];
|
||
|
||
export function usePricingLogic() {
|
||
const navigate = useNavigate();
|
||
const { tierId } = useParams();
|
||
const [searchParams] = useSearchParams();
|
||
const cycle = searchParams.get('cycle') || 'monthly';
|
||
|
||
const [activeTab, setActiveTab] = useState<'personal' | 'enterprise'>('personal');
|
||
const [billingCycle, setBillingCycle] = useState<'monthly' | 'yearly'>(cycle as any);
|
||
const [membership, setMembership] = useState<MembershipInfo | null>(null);
|
||
const [loading, setLoading] = useState(false);
|
||
const [timeLeft, setTimeLeft] = useState(600); // 10 minutes in seconds
|
||
const { message } = AntApp.useApp();
|
||
|
||
// 根据 URL 参数计算当前的支付信息
|
||
const paymentInfo = useMemo(() => {
|
||
if (!tierId) return null;
|
||
const allTiers = [...PERSONAL_TIERS, ...ENTERPRISE_TIERS];
|
||
const tier = allTiers.find(t => t.id === tierId);
|
||
if (!tier) return null;
|
||
return {
|
||
tier,
|
||
duration: cycle === 'monthly' ? 30 : 365
|
||
};
|
||
}, [tierId, cycle]);
|
||
|
||
useEffect(() => {
|
||
loadMembership();
|
||
}, []);
|
||
|
||
useEffect(() => {
|
||
let timer: any;
|
||
if (paymentInfo && timeLeft > 0) {
|
||
timer = setInterval(() => {
|
||
setTimeLeft((prev) => prev - 1);
|
||
}, 1000);
|
||
} else if (timeLeft === 0) {
|
||
navigate('/pricing', { replace: true });
|
||
message.error('支付超时,请重新发起');
|
||
}
|
||
return () => clearInterval(timer);
|
||
}, [paymentInfo, timeLeft, navigate]);
|
||
|
||
const loadMembership = async () => {
|
||
try {
|
||
const info = await MembershipAPI.getMe();
|
||
setMembership(info);
|
||
} catch (e) {
|
||
console.error('Failed to load membership', e);
|
||
}
|
||
};
|
||
|
||
const handleSubscribe = async (tier: PricingTier) => {
|
||
if (tier.price === '面议' || tier.id === 'trial') return;
|
||
|
||
// 使用子路由跳转
|
||
navigate(`/pricing/pay/${tier.id}?cycle=${billingCycle}`);
|
||
setTimeLeft(600);
|
||
};
|
||
|
||
const cancelPayment = () => {
|
||
navigate('/pricing');
|
||
};
|
||
|
||
return {
|
||
activeTab,
|
||
setActiveTab,
|
||
billingCycle,
|
||
setBillingCycle,
|
||
membership,
|
||
loading,
|
||
handleSubscribe,
|
||
paymentInfo,
|
||
timeLeft,
|
||
cancelPayment,
|
||
PERSONAL_TIERS,
|
||
ENTERPRISE_TIERS,
|
||
};
|
||
}
|
||
|
||
export type PricingLogicOutput = ReturnType<typeof usePricingLogic>;
|