fix(web): disable unsupported subscription api calls

This commit is contained in:
Xiaoxia AI
2026-06-22 10:35:24 +08:00
parent 05a7eff584
commit 51a1729c59
3 changed files with 44 additions and 130 deletions
@@ -4,7 +4,18 @@
import React from 'react';
import { Card, Progress, Row, Col, Tag, Space } from 'antd';
import { ProjectOutlined, CloudOutlined, WarningOutlined } from '@ant-design/icons';
import type { QuotaStatus } from '@/api/subscription';
interface QuotaStatus {
projects: {
used: number;
limit: number;
status: string;
};
storage: {
used_gb: number;
limit_gb: number;
status: string;
};
}
interface QuotaDisplayProps {
quota: QuotaStatus;
@@ -1,140 +1,30 @@
/**
* 订阅升级流程页面
*/
import React, { useState } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { Card, Steps, Button, Result, Descriptions, message } from 'antd';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { upgradeSubscription } from '@/api/subscription';
import React from 'react';
import { Button, Card, Result } from 'antd';
import { useNavigate, useParams } from 'react-router-dom';
const UpgradeSubscription: React.FC = () => {
const { workspaceId } = useParams<{ workspaceId: string }>();
const navigate = useNavigate();
const queryClient = useQueryClient();
const [current, setCurrent] = useState(0);
const [selectedPlan, setSelectedPlan] = useState<'pro' | 'enterprise'>('pro');
const upgradeMutation = useMutation({
mutationFn: () => upgradeSubscription(workspaceId!, selectedPlan),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['workspace', workspaceId] });
setCurrent(2);
message.success('订阅升级成功!');
},
onError: (error: any) => {
message.error(error.response?.data?.message || '升级失败');
},
});
const steps = [
{
title: '选择套餐',
content: (
<div>
<Card
style={{ marginBottom: 16, cursor: 'pointer' }}
onClick={() => setSelectedPlan('pro')}
className={selectedPlan === 'pro' ? 'selected-plan' : ''}
>
<h3>Pro 套餐</h3>
<p>¥99/月</p>
<ul>
<li>无限项目</li>
<li>100GB 存储</li>
<li>20 个成员</li>
</ul>
</Card>
<Card
style={{ cursor: 'pointer' }}
onClick={() => setSelectedPlan('enterprise')}
className={selectedPlan === 'enterprise' ? 'selected-plan' : ''}
>
<h3>Enterprise 套餐</h3>
<p>¥999/月</p>
<ul>
<li>无限项目</li>
<li>1TB 存储</li>
<li>无限成员</li>
<li>专属支持</li>
</ul>
</Card>
</div>
),
},
{
title: '确认订单',
content: (
<Card>
<Descriptions column={1}>
<Descriptions.Item label="套餐">
{selectedPlan === 'pro' ? 'Pro' : 'Enterprise'}
</Descriptions.Item>
<Descriptions.Item label="价格">
{selectedPlan === 'pro' ? '¥99' : '¥999'} / 月
</Descriptions.Item>
<Descriptions.Item label="支付方式">
在线支付(待接入)
</Descriptions.Item>
</Descriptions>
</Card>
),
},
{
title: '完成',
content: (
<Result
status="success"
title="升级成功!"
subTitle="您的订阅已升级,新配额已生效。"
extra={[
<Button
type="primary"
key="workspace"
onClick={() => navigate(`/workspaces/${workspaceId}`)}
>
返回工作空间
</Button>,
]}
/>
),
},
];
const next = () => {
if (current === 0) {
setCurrent(current + 1);
} else if (current === 1) {
upgradeMutation.mutate();
}
};
const prev = () => {
setCurrent(current - 1);
};
return (
<div style={{ padding: '24px' }}>
<h1>升级订阅</h1>
<Steps current={current} items={steps} style={{ marginBottom: 24 }} />
<div>{steps[current].content}</div>
<div style={{ marginTop: 24 }}>
{current < steps.length - 1 && (
<>
{current > 0 && (
<Button style={{ marginRight: 8 }} onClick={prev}>
上一步
<Card>
<Result
status="info"
title="订阅升级暂未开放"
subTitle="当前版本未接入订阅、支付和配额变更后端服务。为避免假成功或调用不存在的接口,此入口已暂时关闭。"
extra={[
<Button key="plans" onClick={() => navigate('/subscription')}>
查看套餐说明
</Button>,
workspaceId ? (
<Button key="workspace" type="primary" onClick={() => navigate(`/workspaces/${workspaceId}`)}>
返回工作空间
</Button>
)}
<Button
type="primary"
onClick={next}
loading={upgradeMutation.isPending}
>
{current === 1 ? '确认升级' : '下一步'}
</Button>
</>
)}
</div>
) : null,
]}
/>
</Card>
</div>
);
};
+13
View File
@@ -121,6 +121,19 @@ def test_web_dockerfile_uses_reachable_base_image_mirror():
assert "FROM nginx:alpine" not in dockerfile
def test_subscription_api_is_not_wired_to_ui_until_backend_exists():
source_files = list(Path("apps/web/src").rglob("*.ts")) + list(Path("apps/web/src").rglob("*.tsx"))
importers = []
for path in source_files:
if path.as_posix().endswith("apps/web/src/api/subscription.ts"):
continue
text = path.read_text(encoding="utf-8")
if "@/api/subscription" in text or "../api/subscription" in text:
importers.append(path.as_posix())
assert importers == []
def test_backup_postgres_writes_manifest_and_version():
script = Path("scripts/backup_postgres.sh").read_text(encoding="utf-8")