Prmbr/docs/pricing-page-improvements.md
2025-08-05 23:18:40 +08:00

186 lines
4.5 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 定价页面改进说明
## 概述
定价页面现在实现了智能的套餐过滤和按钮显示逻辑,确保只显示有效的可订阅套餐,并提供清晰的用户体验。
## 主要改进
### 1. 智能套餐过滤
定价页面现在只显示以下套餐:
1. **免费套餐** - 总是显示
2. **用户当前套餐** - 总是显示(即使没有 stripePriceId
3. **有效的付费套餐** - 必须有 `stripePriceId` 才显示
#### 过滤逻辑
```typescript
const filteredPlans = plans.filter((plan: SubscriptionPlan) => {
// 免费套餐总是显示
if (isPlanFree(plan)) return true
// 用户当前套餐总是显示
if (userData && isCurrentPlan(plan.id)) return true
// 其他套餐必须有 stripePriceId 才能显示(可订阅)
return plan.stripePriceId && plan.stripePriceId.trim() !== ''
})
```
### 2. 智能按钮显示
按钮显示遵循以下逻辑:
#### 免费套餐
- **当前套餐**: 显示 "当前方案" 按钮(禁用)
- **非当前套餐**: 不显示任何按钮
#### 付费套餐
- **当前套餐**: 显示 "当前方案" 按钮(禁用)
- **可订阅套餐**: 显示 "立即订阅" 按钮
- **无价格ID套餐**: 不显示按钮(理论上不会出现,因为已过滤)
#### 按钮逻辑代码
```typescript
{(() => {
// 免费套餐逻辑
if (isFree) {
if (isCurrent) {
return <Button variant="outline" disabled>{t('currentPlan')}</Button>
}
return null // 免费套餐且非当前套餐,不显示按钮
}
// 付费套餐逻辑
if (isCurrent) {
return <Button variant="outline" disabled>{t('currentPlan')}</Button>
}
// 可订阅的付费套餐
if (plan.stripePriceId && plan.stripePriceId.trim() !== '') {
return (
<SubscribeButton priceId={plan.stripePriceId} planName={plan.displayName}>
{t('subscribeNow')}
</SubscribeButton>
)
}
return null
})()}
```
### 3. 多语言支持
添加了新的翻译键:
#### 英文 (en.json)
```json
{
"pricing": {
"subscribeNow": "Subscribe Now",
"currentPlan": "Current Plan"
}
}
```
#### 中文 (zh.json)
```json
{
"pricing": {
"subscribeNow": "立即订阅",
"currentPlan": "当前方案"
}
}
```
## 用户体验场景
### 1. 匿名用户
- 看到:免费套餐(无按钮)+ 有价格ID的付费套餐立即订阅按钮
- 不看到没有价格ID的付费套餐
### 2. 免费用户
- 看到:免费套餐(当前方案按钮)+ 有价格ID的付费套餐立即订阅按钮
- 不看到没有价格ID的付费套餐
### 3. Pro 用户
- 看到:免费套餐(无按钮)+ 当前Pro套餐当前方案按钮+ 其他有价格ID的套餐立即订阅按钮
- 不看到没有价格ID的付费套餐
## 技术实现
### 1. 动态数据获取
```typescript
useEffect(() => {
fetchPlans()
}, [userData]) // 依赖 userData确保用户数据加载后再过滤套餐
```
### 2. 套餐判定工具
使用统一的工具函数:
- `isPlanFree(plan)` - 判断是否为免费套餐
- `isPlanPro(plan)` - 判断是否为Pro套餐
- `isCurrentPlan(planId)` - 判断是否为用户当前套餐
### 3. 类型安全
```typescript
const filteredPlans = (data.plans || []).filter((plan: SubscriptionPlan) => {
// 过滤逻辑
})
```
## 配置要求
### 1. 套餐配置
确保付费套餐有有效的 `stripePriceId`
```sql
-- 检查套餐配置
SELECT id, name, "displayName", price, "stripePriceId", "isActive"
FROM subscription_plans
WHERE "isActive" = true;
-- 设置价格ID
UPDATE subscription_plans
SET "stripePriceId" = 'price_your_stripe_price_id'
WHERE name = 'pro';
```
### 2. 验证工具
使用测试脚本验证配置:
```bash
npx tsx scripts/test-pricing-page-filtering.ts
```
## 优势
1. **用户友好**: 只显示用户可以实际订阅的套餐
2. **防止错误**: 避免显示无法订阅的套餐
3. **清晰导航**: 明确的按钮状态和操作
4. **灵活配置**: 支持动态套餐管理
5. **多语言**: 完整的国际化支持
## 故障排除
### 问题:套餐不显示
**原因**: 付费套餐没有设置 `stripePriceId`
**解决**: 在数据库中设置正确的 Stripe 价格 ID
### 问题:按钮不显示
**原因**: 套餐被过滤掉或逻辑判断问题
**解决**: 检查套餐配置和用户状态
### 问题:翻译缺失
**原因**: 缺少 `subscribeNow` 翻译键
**解决**: 在对应语言文件中添加翻译
## 测试建议
1. 测试不同用户状态下的页面显示
2. 验证按钮功能和状态
3. 检查多语言显示
4. 确认套餐过滤逻辑
5. 测试订阅流程