feat(desktop): add billing frontend — plans, subscription, payment flow

Sprint 1: Desktop 计费闭环

- Add 7 billing types to saas-types.ts (BillingPlan, Subscription, UsageQuota, etc.)
- Add 6 billing API methods to saas-billing.ts (listPlans, getSubscription, createPayment, etc.)
- Extend saas-client.ts with interface merging for billing methods
- Extend saasStore with billing state/actions (plans, subscription, payment polling)
- Create PricingPage component with plan cards, usage bars, and checkout modal
- Add billing page entry in SettingsLayout (CreditCard icon + route)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-04-04 10:48:33 +08:00
parent be0a78a523
commit eac1d9449e
6 changed files with 670 additions and 3 deletions

View File

@@ -19,6 +19,7 @@ import {
Key,
Database,
Cloud,
CreditCard,
} from 'lucide-react';
import { silentErrorHandler } from '../../lib/error-utils';
import { General } from './General';
@@ -39,6 +40,7 @@ import { HeartbeatConfig } from '../HeartbeatConfig';
import { SecureStorage } from './SecureStorage';
import { VikingPanel } from '../VikingPanel';
import { SaaSSettings } from '../SaaS/SaaSSettings';
import { PricingPage } from '../SaaS/PricingPage';
interface SettingsLayoutProps {
onBack: () => void;
@@ -57,6 +59,7 @@ type SettingsPage =
| 'security'
| 'storage'
| 'saas'
| 'billing'
| 'viking'
| 'audit'
| 'tasks'
@@ -76,6 +79,7 @@ const menuItems: { id: SettingsPage; label: string; icon: React.ReactNode }[] =
{ id: 'privacy', label: '数据与隐私', icon: <Shield className="w-4 h-4" /> },
{ id: 'storage', label: '安全存储', icon: <Key className="w-4 h-4" /> },
{ id: 'saas', label: 'SaaS 平台', icon: <Cloud className="w-4 h-4" /> },
{ id: 'billing', label: '订阅与计费', icon: <CreditCard className="w-4 h-4" /> },
{ id: 'viking', label: '语义记忆', icon: <Database className="w-4 h-4" /> },
{ id: 'security', label: '安全状态', icon: <Shield className="w-4 h-4" /> },
{ id: 'audit', label: '审计日志', icon: <ClipboardList className="w-4 h-4" /> },
@@ -102,6 +106,7 @@ export function SettingsLayout({ onBack }: SettingsLayoutProps) {
case 'privacy': return <Privacy />;
case 'storage': return <SecureStorage />;
case 'saas': return <SaaSSettings />;
case 'billing': return <PricingPage />;
case 'security': return (
<div className="space-y-6">
<div>