refactor: 重构代码结构和类型定义,优化类型安全性和代码可维护性

- 添加类型定义文件和类型引用
- 删除废弃的页面模块和导出文件
- 新增聚合管理模块和插件系统
- 修复类型错误和潜在运行时问题
- 更新API基础URL和配置
- 优化组件类型定义和事件处理
- 重构数据源接口和实现
- 完善文档和开发进度记录
This commit is contained in:
2026-03-22 11:25:28 +08:00
parent 15ee1758f5
commit a037843851
88 changed files with 42703 additions and 6395 deletions

View File

@@ -0,0 +1,429 @@
import React, { useState } from 'react';
import { Card, Row, Col, Switch, Tag, Typography, Space, Button, Modal, Progress, Divider, Alert, Tabs, Table, message } from 'antd';
import {
CrownOutlined,
RobotOutlined,
ShopOutlined,
GlobalOutlined,
LineChartOutlined,
ApiOutlined,
CheckCircleOutlined,
CloseCircleOutlined,
ThunderboltOutlined,
StarOutlined,
} from '@ant-design/icons';
import { useUser, FEATURES, ROLE_CONFIG } from '@/contexts/UserContext';
const { Title, Text, Paragraph } = Typography;
interface FeatureConfig {
key: string;
name: string;
description: string;
icon: React.ReactNode;
requiredPlan: string[];
benefits: string[];
limitations?: string[];
}
const FEATURE_CONFIGS: FeatureConfig[] = [
{
key: FEATURES.AI_OPERATIONS,
name: 'AI运营中心',
description: '智能运营助手,自动化执行日常运营任务',
icon: <RobotOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['basic', 'pro', 'enterprise'],
benefits: [
'自动选品推荐',
'智能定价策略',
'自动上下架',
'AI决策日志追踪',
'策略市场访问',
],
limitations: [
'免费版: 每日仅3次AI调用',
'基础版: 每日100次AI调用',
'专业版: 无限AI调用',
],
},
{
key: FEATURES.AUTO_PRICING,
name: '自动定价',
description: '基于市场数据和竞争分析的智能定价系统',
icon: <ThunderboltOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['pro', 'enterprise'],
benefits: [
'实时竞品价格监控',
'动态定价策略',
'利润率自动优化',
'价格预警通知',
],
limitations: [
'基础版: 仅查看定价建议',
'专业版: 自动执行定价',
],
},
{
key: FEATURES.MULTI_SHOP,
name: '多店铺管理',
description: '统一管理多个电商平台的店铺',
icon: <ShopOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['basic', 'pro', 'enterprise'],
benefits: [
'跨平台商品同步',
'统一库存管理',
'多店铺数据报表',
'批量操作支持',
],
limitations: [
'免费版: 仅支持1个店铺',
'基础版: 最多3个店铺',
'专业版: 最多10个店铺',
'企业版: 无限店铺',
],
},
{
key: FEATURES.B2B_TRADE,
name: 'B2B贸易',
description: '企业级批发贸易管理功能',
icon: <ShopOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['basic', 'pro', 'enterprise'],
benefits: [
'供应商管理',
'批量订单处理',
'B2B专属定价',
'合同管理',
],
},
{
key: FEATURES.INDEPENDENT_SITE,
name: '独立站',
description: '创建和管理独立电商网站',
icon: <GlobalOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['pro', 'enterprise'],
benefits: [
'自定义品牌站点',
'独立域名绑定',
'SEO优化工具',
'独立支付集成',
],
},
{
key: FEATURES.ADVANCED_ANALYTICS,
name: '高级数据分析',
description: '深度数据分析和可视化报表',
icon: <LineChartOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['pro', 'enterprise'],
benefits: [
'自定义报表',
'数据导出',
'趋势预测',
'竞品分析报告',
],
limitations: [
'基础版: 仅基础报表',
'专业版: 完整分析功能',
],
},
{
key: FEATURES.API_ACCESS,
name: 'API访问',
description: '开放API接口支持系统集成',
icon: <ApiOutlined style={{ fontSize: 24 }} />,
requiredPlan: ['enterprise'],
benefits: [
'RESTful API',
'Webhook支持',
'SDK下载',
'技术文档',
],
},
];
const PLAN_DETAILS = {
free: {
name: '免费版',
price: 0,
color: 'default',
features: ['基础商品管理', '订单管理', '基础报表'],
limitations: ['1个店铺', '每日3次AI调用', '无API访问'],
},
basic: {
name: '基础版',
price: 99,
color: 'blue',
features: ['多店铺管理(3个)', 'AI运营(100次/日)', 'B2B贸易', '基础定价建议'],
limitations: ['无独立站', '无API访问'],
},
pro: {
name: '专业版',
price: 299,
color: 'gold',
features: ['多店铺管理(10个)', '无限AI调用', '自动定价', '独立站', '高级分析'],
limitations: ['无API访问'],
},
enterprise: {
name: '企业版',
price: 999,
color: 'purple',
features: ['无限店铺', '全部功能', 'API访问', '专属客服', '定制开发'],
limitations: [],
},
};
const SubscriptionManage: React.FC = () => {
const { currentUser, hasFeature, isPaidUser, getPlanLabel } = useUser();
const [previewFeature, setPreviewFeature] = useState<FeatureConfig | null>(null);
const [simulatedPlan, setSimulatedPlan] = useState<string | null>(null);
const currentPlan = currentUser.subscription?.plan || 'free';
const handleFeaturePreview = (feature: FeatureConfig) => {
setPreviewFeature(feature);
};
const handleSimulatePlan = (plan: string) => {
setSimulatedPlan(plan);
message.info(`已切换到${PLAN_DETAILS[plan as keyof typeof PLAN_DETAILS].name}预览模式`);
};
const isFeatureAvailable = (featureKey: string) => {
if (simulatedPlan) {
const feature = FEATURE_CONFIGS.find(f => f.key === featureKey);
return feature?.requiredPlan.includes(simulatedPlan) ?? false;
}
return hasFeature(featureKey);
};
const columns = [
{
title: '功能',
dataIndex: 'name',
key: 'name',
render: (name: string, record: FeatureConfig) => (
<Space>
{record.icon}
<span>{name}</span>
</Space>
),
},
{
title: '免费版',
key: 'free',
render: (_: any, record: FeatureConfig) =>
record.requiredPlan.includes('free') ?
<CheckCircleOutlined style={{ color: '#52c41a' }} /> :
<CloseCircleOutlined style={{ color: '#d9d9d9' }} />,
},
{
title: '基础版',
key: 'basic',
render: (_: any, record: FeatureConfig) =>
record.requiredPlan.includes('basic') ?
<CheckCircleOutlined style={{ color: '#52c41a' }} /> :
<CloseCircleOutlined style={{ color: '#d9d9d9' }} />,
},
{
title: '专业版',
key: 'pro',
render: (_: any, record: FeatureConfig) =>
record.requiredPlan.includes('pro') ?
<CheckCircleOutlined style={{ color: '#52c41a' }} /> :
<CloseCircleOutlined style={{ color: '#d9d9d9' }} />,
},
{
title: '企业版',
key: 'enterprise',
render: (_: any, record: FeatureConfig) =>
record.requiredPlan.includes('enterprise') ?
<CheckCircleOutlined style={{ color: '#52c41a' }} /> :
<CloseCircleOutlined style={{ color: '#d9d9d9' }} />,
},
{
title: '当前状态',
key: 'status',
render: (_: any, record: FeatureConfig) => (
<Tag color={isFeatureAvailable(record.key) ? 'green' : 'default'}>
{isFeatureAvailable(record.key) ? '已开通' : '未开通'}
</Tag>
),
},
{
title: '操作',
key: 'action',
render: (_: any, record: FeatureConfig) => (
<Button type="link" onClick={() => handleFeaturePreview(record)}>
</Button>
),
},
];
return (
<div className="subscription-manage">
<div className="page-header" style={{ marginBottom: 24 }}>
<Title level={2}>
<CrownOutlined style={{ marginRight: 8 }} />
</Title>
<Paragraph type="secondary">
</Paragraph>
</div>
<Alert
message="临时预览模式"
description="点击下方套餐卡片可以预览不同套餐的功能权限,实际功能以订阅为准"
type="info"
showIcon
style={{ marginBottom: 24 }}
/>
<Row gutter={16} style={{ marginBottom: 24 }}>
{Object.entries(PLAN_DETAILS).map(([key, plan]) => (
<Col span={6} key={key}>
<Card
hoverable
style={{
borderColor: currentPlan === key ? '#1890ff' : undefined,
borderWidth: currentPlan === key ? 2 : 1,
}}
onClick={() => handleSimulatePlan(key)}
>
<div style={{ textAlign: 'center' }}>
<Tag color={plan.color} style={{ marginBottom: 8 }}>
{plan.name}
</Tag>
{currentPlan === key && (
<Tag color="green" style={{ marginLeft: 4 }}></Tag>
)}
{simulatedPlan === key && currentPlan !== key && (
<Tag color="blue" style={{ marginLeft: 4 }}></Tag>
)}
<Title level={3} style={{ margin: '8px 0' }}>
¥{plan.price}
<Text type="secondary" style={{ fontSize: 14 }}>/</Text>
</Title>
<Divider style={{ margin: '12px 0' }} />
<div style={{ textAlign: 'left' }}>
{plan.features.map((f, i) => (
<div key={i} style={{ marginBottom: 4 }}>
<CheckCircleOutlined style={{ color: '#52c41a', marginRight: 8 }} />
<Text>{f}</Text>
</div>
))}
{plan.limitations.map((l, i) => (
<div key={i} style={{ marginBottom: 4 }}>
<CloseCircleOutlined style={{ color: '#d9d9d9', marginRight: 8 }} />
<Text type="secondary">{l}</Text>
</div>
))}
</div>
</div>
</Card>
</Col>
))}
</Row>
<Card title="功能对比表" style={{ marginBottom: 24 }}>
<Table
columns={columns}
dataSource={FEATURE_CONFIGS}
rowKey="key"
pagination={false}
/>
</Card>
<Card title="当前订阅状态">
<Row gutter={24}>
<Col span={8}>
<div style={{ textAlign: 'center', padding: 24 }}>
<Tag color={PLAN_DETAILS[currentPlan as keyof typeof PLAN_DETAILS]?.color || 'default'} style={{ fontSize: 16, padding: '4px 12px' }}>
{getPlanLabel()}
</Tag>
<Title level={4} style={{ marginTop: 16 }}></Title>
<Text type="secondary">
{currentUser.subscription?.expiresAt ?
`到期时间: ${currentUser.subscription.expiresAt}` :
'永久有效'}
</Text>
</div>
</Col>
<Col span={8}>
<div style={{ textAlign: 'center', padding: 24 }}>
<Title level={2}>{currentUser.subscription?.features.length || 0}</Title>
<Text type="secondary"></Text>
</div>
</Col>
<Col span={8}>
<div style={{ textAlign: 'center', padding: 24 }}>
<Title level={2}>{FEATURE_CONFIGS.filter(f => !hasFeature(f.key)).length}</Title>
<Text type="secondary"></Text>
</div>
</Col>
</Row>
</Card>
<Modal
title={previewFeature?.name}
open={!!previewFeature}
onCancel={() => setPreviewFeature(null)}
footer={[
<Button key="close" onClick={() => setPreviewFeature(null)}>
</Button>,
!isFeatureAvailable(previewFeature?.key || '') && (
<Button key="upgrade" type="primary">
</Button>
),
]}
width={600}
>
{previewFeature && (
<div>
<Paragraph>{previewFeature.description}</Paragraph>
<Title level={5}></Title>
{previewFeature.benefits.map((b, i) => (
<div key={i} style={{ marginBottom: 8 }}>
<CheckCircleOutlined style={{ color: '#52c41a', marginRight: 8 }} />
{b}
</div>
))}
{previewFeature.limitations && (
<>
<Title level={5} style={{ marginTop: 16 }}></Title>
{previewFeature.limitations.map((l, i) => (
<div key={i} style={{ marginBottom: 8 }}>
<Text type="secondary"> {l}</Text>
</div>
))}
</>
)}
<Divider />
<Title level={5}></Title>
<Space>
{previewFeature.requiredPlan.map(p => (
<Tag key={p} color={PLAN_DETAILS[p as keyof typeof PLAN_DETAILS]?.color}>
{PLAN_DETAILS[p as keyof typeof PLAN_DETAILS]?.name}
</Tag>
))}
</Space>
<div style={{ marginTop: 16 }}>
<Tag color={isFeatureAvailable(previewFeature.key) ? 'green' : 'orange'}>
{isFeatureAvailable(previewFeature.key) ? '✓ 您已拥有此功能' : '✗ 需要升级套餐'}
</Tag>
</div>
</div>
)}
</Modal>
</div>
);
};
export default SubscriptionManage;