refactor(StockCompareModal): 重构为 Ant Design 并统一主题配置

- 从 Chakra UI 迁移到 Ant Design (Modal, Table, Card)
- 新增 antdTheme.ts 统一 Ant Design 深色主题配置
- 提取 calculateDiff 到 FinancialPanorama/utils 复用
- 使用 useMemo 优化性能,提取子组件
- 添加独立的 .less 样式文件

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-12-26 13:59:44 +08:00
parent 086cc3cddb
commit c1394dbf19
6 changed files with 603 additions and 204 deletions

View File

@@ -97,3 +97,28 @@ export const isNegativeIndicator = (key: string): boolean => {
key.includes('debt_ratio')
);
};
/**
* 计算两个值的差异百分比
* @param value1 当前股票值
* @param value2 对比股票值
* @param format 格式类型percent 直接相减number 计算变化率
* @returns 差异百分比或 null
*/
export const calculateDiff = (
value1: number | null | undefined,
value2: number | null | undefined,
format: 'percent' | 'number'
): number | null => {
if (value1 == null || value2 == null) return null;
if (format === 'percent') {
return value1 - value2;
}
if (value2 !== 0) {
return ((value1 - value2) / Math.abs(value2)) * 100;
}
return null;
};

View File

@@ -7,6 +7,7 @@ export {
getCellBackground,
getValueByPath,
isNegativeIndicator,
calculateDiff,
} from './calculations';
export {

View File

@@ -0,0 +1,16 @@
/**
* StockCompareModal 样式
*/
// 禁用表格行 hover 效果
.compare-table-row {
> td {
background: transparent !important;
}
}
.ant-table-tbody > tr.compare-table-row:hover > td,
.ant-table-tbody > tr.compare-table-row:hover > td.ant-table-cell,
.ant-table-tbody > tr.compare-table-row > td.ant-table-cell-row-hover {
background: transparent !important;
}

View File

@@ -1,43 +1,36 @@
/**
* StockCompareModal - 股票对比弹窗组件
* 展示对比明细、盈利能力对比、成长力对比
*
* 使用 Ant Design Modal + Table
* 主题配置使用 Company/theme 统一配置
*/
import React from 'react';
import {
Modal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalBody,
ModalCloseButton,
VStack,
HStack,
Grid,
GridItem,
Card,
CardHeader,
CardBody,
Heading,
Text,
Table,
Thead,
Tbody,
Tr,
Th,
Td,
TableContainer,
Spinner,
Center,
} from '@chakra-ui/react';
import { ArrowUp, ArrowDown } from 'lucide-react';
import React, { useMemo } from 'react';
import { Modal, Table, Spin, Row, Col, Card, Typography, Space, ConfigProvider } from 'antd';
import type { ColumnsType } from 'antd/es/table';
import { ArrowUpOutlined, ArrowDownOutlined } from '@ant-design/icons';
import ReactECharts from 'echarts-for-react';
import { COMPARE_METRICS } from '../../FinancialPanorama/constants';
import { getValueByPath, getCompareBarChartOption } from '../../FinancialPanorama/utils';
import { getValueByPath, getCompareBarChartOption, calculateDiff } from '../../FinancialPanorama/utils';
import { formatUtils } from '@services/financialService';
import type { StockInfo } from '../../FinancialPanorama/types';
import {
antdDarkTheme,
modalStyles,
cardStyle,
cardStyles,
chartCardStyles,
FUI_COLORS,
} from '../../../theme';
import './StockCompareModal.less';
const { Title, Text } = Typography;
// ============================================
// 类型定义
// ============================================
interface StockCompareModalProps {
isOpen: boolean;
onClose: () => void;
@@ -48,6 +41,70 @@ interface StockCompareModalProps {
isLoading?: boolean;
}
interface CompareTableRow {
key: string;
metric: string;
currentValue: number | null | undefined;
compareValue: number | null | undefined;
diff: number | null;
format: 'percent' | 'number';
}
// ============================================
// 工具函数
// ============================================
const formatValue = (
value: number | null | undefined,
format: 'percent' | 'number'
): string => {
if (value == null) return '-';
return format === 'percent'
? formatUtils.formatPercent(value)
: formatUtils.formatLargeNumber(value);
};
// ============================================
// 子组件
// ============================================
const DiffCell: React.FC<{ diff: number | null }> = ({ diff }) => {
if (diff === null) return <span style={{ color: FUI_COLORS.text.muted }}>-</span>;
const isPositive = diff > 0;
const color = isPositive ? FUI_COLORS.status.positive : FUI_COLORS.status.negative;
const Icon = isPositive ? ArrowUpOutlined : ArrowDownOutlined;
return (
<Space size={4} style={{ color, justifyContent: 'center' }}>
<Icon style={{ fontSize: 11 }} />
<span style={{ fontWeight: 500 }}>{Math.abs(diff).toFixed(2)}%</span>
</Space>
);
};
const CardTitle: React.FC<{ children: React.ReactNode }> = ({ children }) => (
<Title level={5} style={{ margin: 0, color: FUI_COLORS.gold[400], fontSize: 14 }}>
{children}
</Title>
);
const LoadingState: React.FC = () => (
<div style={{ textAlign: 'center', padding: '80px 0' }}>
<Spin size="large" />
<Text style={{ display: 'block', marginTop: 16, color: FUI_COLORS.text.muted }}>
...
</Text>
</div>
);
const EmptyState: React.FC = () => (
<div style={{ textAlign: 'center', padding: '80px 0' }}>
<Text style={{ color: FUI_COLORS.text.muted, fontSize: 14 }}></Text>
</div>
);
// ============================================
// 主组件
// ============================================
const StockCompareModal: React.FC<StockCompareModalProps> = ({
isOpen,
onClose,
@@ -57,185 +114,203 @@ const StockCompareModal: React.FC<StockCompareModalProps> = ({
compareStockInfo,
isLoading = false,
}) => {
// 黑金主题颜色
const bgColor = '#1A202C';
const borderColor = '#C9A961';
const goldColor = '#F4D03F';
const positiveColor = '#EF4444'; // 红涨
const negativeColor = '#10B981'; // 绿跌
// 构建表格数据
const tableData = useMemo<CompareTableRow[]>(() => {
if (!currentStockInfo || !compareStockInfo) return [];
// 加载中或无数据时的显示
if (isLoading || !currentStockInfo || !compareStockInfo) {
return (
<Modal isOpen={isOpen} onClose={onClose} size="5xl" scrollBehavior="inside">
<ModalOverlay />
<ModalContent bg={bgColor} borderColor={borderColor} borderWidth="1px">
<ModalHeader color={goldColor}></ModalHeader>
<ModalCloseButton color={borderColor} />
<ModalBody pb={6}>
<Center py={20}>
{isLoading ? (
<VStack spacing={4}>
<Spinner size="xl" color={goldColor} />
<Text color={borderColor}>...</Text>
</VStack>
) : (
<Text color={borderColor}></Text>
)}
</Center>
</ModalBody>
</ModalContent>
</Modal>
return COMPARE_METRICS.map((metric) => {
const currentValue = getValueByPath<number>(currentStockInfo, metric.path);
const compareValue = getValueByPath<number>(compareStockInfo, metric.path);
const format = (metric.format || 'number') as 'percent' | 'number';
return {
key: metric.key,
metric: metric.label,
currentValue,
compareValue,
diff: calculateDiff(currentValue, compareValue, format),
format,
};
});
}, [currentStockInfo, compareStockInfo]);
// 表格列定义
const columns = useMemo<ColumnsType<CompareTableRow>>(() => [
{
title: '指标',
dataIndex: 'metric',
key: 'metric',
align: 'center',
width: '25%',
render: (text) => <span style={{ color: FUI_COLORS.text.muted }}>{text}</span>,
},
{
title: currentStockInfo?.stock_name || currentStock,
dataIndex: 'currentValue',
key: 'currentValue',
align: 'center',
width: '25%',
render: (value, record) => (
<span style={{ color: FUI_COLORS.gold[400], fontWeight: 500 }}>
{formatValue(value, record.format)}
</span>
),
},
{
title: compareStockInfo?.stock_name || compareStock,
dataIndex: 'compareValue',
key: 'compareValue',
align: 'center',
width: '25%',
render: (value, record) => (
<span style={{ color: FUI_COLORS.gold[400], fontWeight: 500 }}>
{formatValue(value, record.format)}
</span>
),
},
{
title: '差异',
dataIndex: 'diff',
key: 'diff',
align: 'center',
width: '25%',
render: (diff: number | null) => <DiffCell diff={diff} />,
},
], [currentStock, compareStock, currentStockInfo?.stock_name, compareStockInfo?.stock_name]);
// 盈利能力图表配置
const profitabilityChartOption = useMemo(() => {
if (!currentStockInfo || !compareStockInfo) return {};
return getCompareBarChartOption(
'盈利能力对比',
currentStockInfo.stock_name || '',
compareStockInfo.stock_name || '',
['ROE', 'ROA', '毛利率', '净利率'],
[
currentStockInfo.key_metrics?.roe,
currentStockInfo.key_metrics?.roa,
currentStockInfo.key_metrics?.gross_margin,
currentStockInfo.key_metrics?.net_margin,
],
[
compareStockInfo.key_metrics?.roe,
compareStockInfo.key_metrics?.roa,
compareStockInfo.key_metrics?.gross_margin,
compareStockInfo.key_metrics?.net_margin,
]
);
}
}, [currentStockInfo, compareStockInfo]);
// 成长能力图表配置
const growthChartOption = useMemo(() => {
if (!currentStockInfo || !compareStockInfo) return {};
return getCompareBarChartOption(
'成长能力对比',
currentStockInfo.stock_name || '',
compareStockInfo.stock_name || '',
['营收增长', '利润增长', '资产增长', '权益增长'],
[
currentStockInfo.growth_rates?.revenue_growth,
currentStockInfo.growth_rates?.profit_growth,
currentStockInfo.growth_rates?.asset_growth,
currentStockInfo.growth_rates?.equity_growth,
],
[
compareStockInfo.growth_rates?.revenue_growth,
compareStockInfo.growth_rates?.profit_growth,
compareStockInfo.growth_rates?.asset_growth,
compareStockInfo.growth_rates?.equity_growth,
]
);
}, [currentStockInfo, compareStockInfo]);
// Modal 标题
const modalTitle = useMemo(() => {
if (!currentStockInfo || !compareStockInfo) return '股票对比';
return `${currentStockInfo.stock_name} (${currentStock}) vs ${compareStockInfo.stock_name} (${compareStock})`;
}, [currentStock, compareStock, currentStockInfo, compareStockInfo]);
// 渲染内容
const renderContent = () => {
if (isLoading) return <LoadingState />;
if (!currentStockInfo || !compareStockInfo) return <EmptyState />;
return (
<Space direction="vertical" size={20} style={{ width: '100%' }}>
{/* 对比明细表格 */}
<Card
title={<CardTitle></CardTitle>}
variant="borderless"
style={cardStyle}
styles={{
...cardStyles,
body: { padding: '12px 0' },
}}
>
<Table
columns={columns}
dataSource={tableData}
pagination={false}
size="middle"
showHeader
rowClassName={() => 'compare-table-row'}
style={{ background: 'transparent' }}
/>
</Card>
{/* 对比图表 */}
<Row gutter={16}>
<Col span={12}>
<Card
title={<CardTitle></CardTitle>}
variant="borderless"
style={cardStyle}
styles={chartCardStyles}
>
<ReactECharts
option={profitabilityChartOption}
style={{ height: 280 }}
notMerge
/>
</Card>
</Col>
<Col span={12}>
<Card
title={<CardTitle></CardTitle>}
variant="borderless"
style={cardStyle}
styles={chartCardStyles}
>
<ReactECharts
option={growthChartOption}
style={{ height: 280 }}
notMerge
/>
</Card>
</Col>
</Row>
</Space>
);
};
return (
<Modal isOpen={isOpen} onClose={onClose} size="5xl" scrollBehavior="inside">
<ModalOverlay />
<ModalContent bg={bgColor} borderColor={borderColor} borderWidth="1px">
<ModalHeader color={goldColor}>
{currentStockInfo?.stock_name} ({currentStock}) vs {compareStockInfo?.stock_name} ({compareStock})
</ModalHeader>
<ModalCloseButton color={borderColor} />
<ModalBody pb={6}>
<VStack spacing={6} align="stretch">
{/* 对比明细表格 */}
<Card bg={bgColor} borderColor={borderColor} borderWidth="1px">
<CardHeader pb={2}>
<Heading size="sm" color={goldColor}></Heading>
</CardHeader>
<CardBody pt={0}>
<TableContainer>
<Table size="sm" variant="unstyled">
<Thead>
<Tr borderBottom="1px solid" borderColor={borderColor}>
<Th color={borderColor} fontSize="xs"></Th>
<Th isNumeric color={borderColor} fontSize="xs">{currentStockInfo?.stock_name}</Th>
<Th isNumeric color={borderColor} fontSize="xs">{compareStockInfo?.stock_name}</Th>
<Th isNumeric color={borderColor} fontSize="xs"></Th>
</Tr>
</Thead>
<Tbody>
{COMPARE_METRICS.map((metric) => {
const value1 = getValueByPath<number>(currentStockInfo, metric.path);
const value2 = getValueByPath<number>(compareStockInfo, metric.path);
let diff: number | null = null;
let diffColor = borderColor;
if (value1 !== undefined && value2 !== undefined && value1 !== null && value2 !== null) {
if (metric.format === 'percent') {
diff = value1 - value2;
diffColor = diff > 0 ? positiveColor : negativeColor;
} else if (value2 !== 0) {
diff = ((value1 - value2) / Math.abs(value2)) * 100;
diffColor = diff > 0 ? positiveColor : negativeColor;
}
}
return (
<Tr key={metric.key} borderBottom="1px solid" borderColor="whiteAlpha.100">
<Td color={borderColor} fontSize="sm">{metric.label}</Td>
<Td isNumeric color={goldColor} fontSize="sm">
{metric.format === 'percent'
? formatUtils.formatPercent(value1)
: formatUtils.formatLargeNumber(value1)}
</Td>
<Td isNumeric color={goldColor} fontSize="sm">
{metric.format === 'percent'
? formatUtils.formatPercent(value2)
: formatUtils.formatLargeNumber(value2)}
</Td>
<Td isNumeric color={diffColor} fontSize="sm">
{diff !== null ? (
<HStack spacing={1} justify="flex-end">
{diff > 0 && <ArrowUp size={12} />}
{diff < 0 && <ArrowDown size={12} />}
<Text>
{`${Math.abs(diff).toFixed(2)}%`}
</Text>
</HStack>
) : (
'-'
)}
</Td>
</Tr>
);
})}
</Tbody>
</Table>
</TableContainer>
</CardBody>
</Card>
{/* 对比图表 */}
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
<GridItem>
<Card bg={bgColor} borderColor={borderColor} borderWidth="1px">
<CardHeader pb={2}>
<Heading size="sm" color={goldColor}></Heading>
</CardHeader>
<CardBody pt={0}>
<ReactECharts
option={getCompareBarChartOption(
'盈利能力对比',
currentStockInfo?.stock_name || '',
compareStockInfo?.stock_name || '',
['ROE', 'ROA', '毛利率', '净利率'],
[
currentStockInfo?.key_metrics?.roe,
currentStockInfo?.key_metrics?.roa,
currentStockInfo?.key_metrics?.gross_margin,
currentStockInfo?.key_metrics?.net_margin,
],
[
compareStockInfo?.key_metrics?.roe,
compareStockInfo?.key_metrics?.roa,
compareStockInfo?.key_metrics?.gross_margin,
compareStockInfo?.key_metrics?.net_margin,
]
)}
style={{ height: '280px' }}
/>
</CardBody>
</Card>
</GridItem>
<GridItem>
<Card bg={bgColor} borderColor={borderColor} borderWidth="1px">
<CardHeader pb={2}>
<Heading size="sm" color={goldColor}></Heading>
</CardHeader>
<CardBody pt={0}>
<ReactECharts
option={getCompareBarChartOption(
'成长能力对比',
currentStockInfo?.stock_name || '',
compareStockInfo?.stock_name || '',
['营收增长', '利润增长', '资产增长', '股东权益增长'],
[
currentStockInfo?.growth_rates?.revenue_growth,
currentStockInfo?.growth_rates?.profit_growth,
currentStockInfo?.growth_rates?.asset_growth,
currentStockInfo?.growth_rates?.equity_growth,
],
[
compareStockInfo?.growth_rates?.revenue_growth,
compareStockInfo?.growth_rates?.profit_growth,
compareStockInfo?.growth_rates?.asset_growth,
compareStockInfo?.growth_rates?.equity_growth,
]
)}
style={{ height: '280px' }}
/>
</CardBody>
</Card>
</GridItem>
</Grid>
</VStack>
</ModalBody>
</ModalContent>
</Modal>
<ConfigProvider theme={antdDarkTheme}>
<Modal
open={isOpen}
onCancel={onClose}
title={modalTitle}
footer={null}
width={1000}
centered
destroyOnHidden
styles={modalStyles}
>
{renderContent()}
</Modal>
</ConfigProvider>
);
};

View File

@@ -0,0 +1,270 @@
/**
* Company 页面 Ant Design 主题配置
*
* 与 FUI 主题系统保持一致的 Ant Design ConfigProvider 主题配置
*
* @example
* import { antdDarkTheme, modalStyles, cardStyle } from '@views/Company/theme/antdTheme';
*
* <ConfigProvider theme={antdDarkTheme}>
* <Modal styles={modalStyles}>...</Modal>
* </ConfigProvider>
*/
import { theme } from 'antd';
import { FUI_COLORS, FUI_GLOW, FUI_GLASS } from './fui';
import { alpha, fui } from './utils';
// ============================================
// Ant Design 深空主题 Token
// ============================================
export const antdDarkTheme = {
algorithm: theme.darkAlgorithm,
token: {
// 主色调
colorPrimary: FUI_COLORS.gold[400],
colorPrimaryHover: FUI_COLORS.gold[300],
colorPrimaryActive: FUI_COLORS.gold[500],
// 背景色
colorBgBase: FUI_COLORS.bg.deep,
colorBgContainer: FUI_COLORS.bg.elevated,
colorBgElevated: FUI_COLORS.bg.surface,
colorBgLayout: FUI_COLORS.bg.primary,
colorBgMask: 'rgba(0, 0, 0, 0.6)',
// 边框
colorBorder: fui.border('default'),
colorBorderSecondary: fui.border('subtle'),
// 文字
colorText: FUI_COLORS.text.primary,
colorTextSecondary: FUI_COLORS.text.secondary,
colorTextTertiary: FUI_COLORS.text.muted,
colorTextQuaternary: FUI_COLORS.text.dim,
colorTextHeading: FUI_COLORS.gold[400],
// 链接
colorLink: FUI_COLORS.gold[400],
colorLinkHover: FUI_COLORS.gold[300],
colorLinkActive: FUI_COLORS.gold[500],
// 成功/错误状态(涨跌色)
colorSuccess: FUI_COLORS.status.negative, // 绿色
colorError: FUI_COLORS.status.positive, // 红色
colorWarning: FUI_COLORS.status.warning,
colorInfo: FUI_COLORS.status.info,
// 圆角
borderRadius: 8,
borderRadiusLG: 12,
borderRadiusSM: 6,
borderRadiusXS: 4,
// 字体
fontFamily: 'inherit',
fontSize: 14,
// 间距
padding: 16,
paddingLG: 24,
paddingSM: 12,
paddingXS: 8,
},
components: {
// Modal 组件
Modal: {
headerBg: FUI_COLORS.bg.deep,
contentBg: FUI_COLORS.bg.deep,
footerBg: FUI_COLORS.bg.deep,
titleColor: FUI_COLORS.gold[400],
titleFontSize: 18,
colorIcon: FUI_COLORS.text.muted,
colorIconHover: FUI_COLORS.gold[400],
},
// Table 组件
Table: {
headerBg: alpha('gold', 0.05),
headerColor: FUI_COLORS.text.muted,
headerSplitColor: fui.border('subtle'),
rowHoverBg: alpha('gold', 0.1),
rowSelectedBg: alpha('gold', 0.15),
rowSelectedHoverBg: alpha('gold', 0.18),
borderColor: fui.border('subtle'),
cellFontSize: 13,
cellPaddingBlock: 14,
cellPaddingInline: 16,
},
// Card 组件
Card: {
headerBg: 'transparent',
colorBgContainer: FUI_COLORS.bg.elevated,
colorBorderSecondary: fui.border('default'),
paddingLG: 16,
},
// Button 组件
Button: {
primaryColor: FUI_COLORS.bg.deep,
colorPrimaryHover: FUI_COLORS.gold[300],
colorPrimaryActive: FUI_COLORS.gold[500],
defaultBg: 'transparent',
defaultBorderColor: fui.border('default'),
defaultColor: FUI_COLORS.text.secondary,
},
// Input 组件
Input: {
colorBgContainer: FUI_COLORS.bg.primary,
colorBorder: fui.border('default'),
hoverBorderColor: fui.border('hover'),
activeBorderColor: FUI_COLORS.gold[400],
activeShadow: FUI_GLOW.gold.sm,
},
// Select 组件
Select: {
colorBgContainer: FUI_COLORS.bg.primary,
colorBorder: fui.border('default'),
optionSelectedBg: alpha('gold', 0.15),
},
// Spin 组件
Spin: {
colorPrimary: FUI_COLORS.gold[400],
},
// Tabs 组件
Tabs: {
inkBarColor: FUI_COLORS.gold[400],
itemActiveColor: FUI_COLORS.gold[400],
itemHoverColor: FUI_COLORS.gold[300],
itemSelectedColor: FUI_COLORS.gold[400],
},
// Tag 组件
Tag: {
defaultBg: alpha('gold', 0.1),
defaultColor: FUI_COLORS.gold[400],
},
// Tooltip 组件
Tooltip: {
colorBgSpotlight: FUI_COLORS.bg.surface,
colorTextLightSolid: FUI_COLORS.text.primary,
},
// Divider 组件
Divider: {
colorSplit: fui.border('subtle'),
},
},
};
// ============================================
// 组件样式预设
// ============================================
/**
* Modal 样式配置
* 用于 Modal 组件的 styles 属性
*/
export const modalStyles = {
mask: {
backdropFilter: FUI_GLASS.blur.md,
},
content: {
background: FUI_COLORS.bg.deep,
border: fui.glassBorder('default'),
borderRadius: 16,
boxShadow: FUI_GLOW.gold.md,
},
header: {
background: 'transparent',
borderBottom: fui.glassBorder('subtle'),
padding: '16px 24px',
},
body: {
padding: 24,
maxHeight: 'calc(100vh - 200px)',
overflowY: 'auto' as const,
},
footer: {
background: 'transparent',
borderTop: fui.glassBorder('subtle'),
padding: '12px 24px',
},
};
/**
* 玻璃卡片样式
* 用于 Card 组件的 style 属性
*/
export const cardStyle = {
background: FUI_COLORS.bg.elevated,
border: fui.glassBorder('default'),
borderRadius: 12,
};
/**
* Card 内部样式配置
* 用于 Card 组件的 styles 属性
*/
export const cardStyles = {
header: {
borderBottom: fui.glassBorder('subtle'),
padding: '12px 16px',
},
body: {
padding: 16,
},
};
/**
* 图表卡片样式配置
*/
export const chartCardStyles = {
header: {
borderBottom: fui.glassBorder('subtle'),
padding: '12px 16px',
},
body: {
padding: 12,
},
};
/**
* 表格样式
* 用于 Table 组件的 style 属性
*/
export const tableStyle = {
background: 'transparent',
};
// ============================================
// 工具函数
// ============================================
/**
* 创建自定义 Ant Design 主题
* 可在基础主题上覆盖特定配置
*/
export function createAntdTheme(overrides?: Partial<typeof antdDarkTheme>) {
return {
...antdDarkTheme,
...overrides,
token: {
...antdDarkTheme.token,
...overrides?.token,
},
components: {
...antdDarkTheme.components,
...overrides?.components,
},
};
}
export default antdDarkTheme;

View File

@@ -5,6 +5,7 @@
* import { COLORS, GLOW, GLASS } from '@views/Company/theme';
* import { FUI_COLORS, FUI_THEME } from '@views/Company/theme';
* import { alpha, fui, chartTheme } from '@views/Company/theme';
* import { antdDarkTheme, modalStyles, cardStyle } from '@views/Company/theme';
*/
// 完整主题对象
@@ -18,6 +19,17 @@ export {
FUI_STYLES,
} from './fui';
// Ant Design 主题配置
export {
antdDarkTheme,
modalStyles,
cardStyle,
cardStyles,
chartCardStyles,
tableStyle,
createAntdTheme,
} from './antdTheme';
// 主题组件
export * from './components';