style(MainBusinessAnalysis): 优化历史对比表格布局
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,18 +4,9 @@
|
||||
|
||||
import React, { useMemo } from 'react';
|
||||
import {
|
||||
VStack,
|
||||
Grid,
|
||||
GridItem,
|
||||
Flex,
|
||||
Box,
|
||||
Heading,
|
||||
Table,
|
||||
Thead,
|
||||
Tbody,
|
||||
Tr,
|
||||
Th,
|
||||
Td,
|
||||
TableContainer,
|
||||
Alert,
|
||||
AlertIcon,
|
||||
} from '@chakra-ui/react';
|
||||
@@ -45,7 +36,7 @@ const BLACK_GOLD_THEME = {
|
||||
algorithm: antTheme.darkAlgorithm,
|
||||
token: {
|
||||
colorPrimary: '#D4AF37',
|
||||
colorBgContainer: 'transparent',
|
||||
colorBgContainer: '#1A202C',
|
||||
colorBgElevated: '#1a1a2e',
|
||||
colorBorder: 'rgba(212, 175, 55, 0.3)',
|
||||
colorText: '#e0e0e0',
|
||||
@@ -65,41 +56,79 @@ const BLACK_GOLD_THEME = {
|
||||
},
|
||||
};
|
||||
|
||||
// 历史对比表格数据行类型
|
||||
// 固定列背景样式(防止滚动时内容重叠)
|
||||
const fixedColumnStyles = `
|
||||
.main-business-table .ant-table-cell-fix-left,
|
||||
.main-business-table .ant-table-cell-fix-right {
|
||||
background: #1A202C !important;
|
||||
}
|
||||
.main-business-table .ant-table-thead .ant-table-cell-fix-left,
|
||||
.main-business-table .ant-table-thead .ant-table-cell-fix-right {
|
||||
background: rgba(26, 32, 44, 0.95) !important;
|
||||
}
|
||||
.main-business-table .ant-table-tbody > tr:hover .ant-table-cell-fix-left,
|
||||
.main-business-table .ant-table-tbody > tr:hover .ant-table-cell-fix-right {
|
||||
background: rgba(212, 175, 55, 0.08) !important;
|
||||
}
|
||||
`;
|
||||
|
||||
// 历史对比表格数据行类型(包含业务明细)
|
||||
interface HistoricalRowData {
|
||||
key: string;
|
||||
business: string;
|
||||
grossMargin?: number;
|
||||
profit?: number;
|
||||
[period: string]: string | number | undefined;
|
||||
}
|
||||
|
||||
// 历史对比表格组件
|
||||
// 历史对比表格组件(整合业务明细)
|
||||
interface HistoricalComparisonTableProps {
|
||||
historicalData: (ProductClassification | IndustryClassification)[];
|
||||
businessItems: BusinessItem[];
|
||||
hasProductData: boolean;
|
||||
latestReportType: string;
|
||||
}
|
||||
|
||||
const HistoricalComparisonTable: React.FC<HistoricalComparisonTableProps> = ({
|
||||
historicalData,
|
||||
businessItems,
|
||||
hasProductData,
|
||||
latestReportType,
|
||||
}) => {
|
||||
// 动态生成列配置
|
||||
const columns: ColumnsType<HistoricalRowData> = useMemo(() => {
|
||||
const cols: ColumnsType<HistoricalRowData> = [
|
||||
{
|
||||
title: '业务/期间',
|
||||
title: '业务',
|
||||
dataIndex: 'business',
|
||||
key: 'business',
|
||||
fixed: 'left',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: `毛利率(${latestReportType})`,
|
||||
dataIndex: 'grossMargin',
|
||||
key: 'grossMargin',
|
||||
align: 'right',
|
||||
width: 120,
|
||||
render: (value: number | undefined) =>
|
||||
value !== undefined ? formatUtils.formatPercent(value) : '-',
|
||||
},
|
||||
{
|
||||
title: `利润(${latestReportType})`,
|
||||
dataIndex: 'profit',
|
||||
key: 'profit',
|
||||
align: 'right',
|
||||
width: 100,
|
||||
render: (value: number | undefined) =>
|
||||
value !== undefined ? formatUtils.formatLargeNumber(value) : '-',
|
||||
},
|
||||
];
|
||||
|
||||
// 添加各期间列
|
||||
// 添加各期间营收列
|
||||
historicalData.slice(0, 4).forEach((period) => {
|
||||
cols.push({
|
||||
title: period.report_type,
|
||||
title: `营收(${period.report_type})`,
|
||||
dataIndex: period.period,
|
||||
key: period.period,
|
||||
align: 'right',
|
||||
@@ -112,9 +141,9 @@ const HistoricalComparisonTable: React.FC<HistoricalComparisonTableProps> = ({
|
||||
});
|
||||
|
||||
return cols;
|
||||
}, [historicalData]);
|
||||
}, [historicalData, latestReportType]);
|
||||
|
||||
// 生成表格数据
|
||||
// 生成表格数据(包含业务明细)
|
||||
const dataSource: HistoricalRowData[] = useMemo(() => {
|
||||
return businessItems
|
||||
.filter((item: BusinessItem) => item.content !== '合计')
|
||||
@@ -122,8 +151,11 @@ const HistoricalComparisonTable: React.FC<HistoricalComparisonTableProps> = ({
|
||||
const row: HistoricalRowData = {
|
||||
key: `${idx}`,
|
||||
business: item.content,
|
||||
grossMargin: item.gross_margin || item.profit_margin,
|
||||
profit: item.profit,
|
||||
};
|
||||
|
||||
// 添加各期间营收数据
|
||||
historicalData.slice(0, 4).forEach((period) => {
|
||||
const periodItems: BusinessItem[] = hasProductData
|
||||
? (period as ProductClassification).products
|
||||
@@ -145,13 +177,16 @@ const HistoricalComparisonTable: React.FC<HistoricalComparisonTableProps> = ({
|
||||
borderColor={THEME.border}
|
||||
borderRadius="md"
|
||||
overflow="hidden"
|
||||
h="100%"
|
||||
className="main-business-table"
|
||||
>
|
||||
<style>{fixedColumnStyles}</style>
|
||||
<Box px={4} py={3} borderBottom="1px solid" borderColor={THEME.border}>
|
||||
<Heading size="sm" color={THEME.headingColor}>
|
||||
主营业务历史对比
|
||||
主营业务明细与历史对比
|
||||
</Heading>
|
||||
</Box>
|
||||
<Box p={4}>
|
||||
<Box p={4} overflowX="auto">
|
||||
<ConfigProvider theme={BLACK_GOLD_THEME}>
|
||||
<AntTable<HistoricalRowData>
|
||||
columns={columns}
|
||||
@@ -218,77 +253,35 @@ export const MainBusinessAnalysis: React.FC<MainBusinessAnalysisProps> = ({
|
||||
: (mainBusiness!.industry_classification! as IndustryClassification[]);
|
||||
|
||||
return (
|
||||
<VStack spacing={4} align="stretch">
|
||||
<Grid templateColumns="repeat(2, 1fr)" gap={4}>
|
||||
<GridItem>
|
||||
<Box
|
||||
bg={THEME.cardBg}
|
||||
border="1px solid"
|
||||
borderColor={THEME.border}
|
||||
borderRadius="md"
|
||||
p={4}
|
||||
>
|
||||
<ReactECharts option={pieOption} style={{ height: '300px' }} />
|
||||
</Box>
|
||||
</GridItem>
|
||||
<GridItem>
|
||||
<Box
|
||||
bg={THEME.cardBg}
|
||||
border="1px solid"
|
||||
borderColor={THEME.border}
|
||||
borderRadius="md"
|
||||
overflow="hidden"
|
||||
>
|
||||
<Box px={4} py={3} borderBottom="1px solid" borderColor={THEME.border}>
|
||||
<Heading size="sm" color={THEME.headingColor}>
|
||||
业务明细 - {latestPeriod.report_type}
|
||||
</Heading>
|
||||
</Box>
|
||||
<Box p={4}>
|
||||
<TableContainer>
|
||||
<Table size="sm">
|
||||
<Thead>
|
||||
<Tr>
|
||||
<Th color={THEME.thColor} borderColor={THEME.border}>业务</Th>
|
||||
<Th isNumeric color={THEME.thColor} borderColor={THEME.border}>营收</Th>
|
||||
<Th isNumeric color={THEME.thColor} borderColor={THEME.border}>毛利率(%)</Th>
|
||||
<Th isNumeric color={THEME.thColor} borderColor={THEME.border}>利润</Th>
|
||||
</Tr>
|
||||
</Thead>
|
||||
<Tbody>
|
||||
{businessItems
|
||||
.filter((item: BusinessItem) => item.content !== '合计')
|
||||
.map((item: BusinessItem, idx: number) => (
|
||||
<Tr key={idx}>
|
||||
<Td color={THEME.textColor} borderColor={THEME.border}>{item.content}</Td>
|
||||
<Td isNumeric color={THEME.textColor} borderColor={THEME.border}>
|
||||
{formatUtils.formatLargeNumber(item.revenue)}
|
||||
</Td>
|
||||
<Td isNumeric color={THEME.textColor} borderColor={THEME.border}>
|
||||
{formatUtils.formatPercent(item.gross_margin || item.profit_margin)}
|
||||
</Td>
|
||||
<Td isNumeric color={THEME.textColor} borderColor={THEME.border}>
|
||||
{formatUtils.formatLargeNumber(item.profit)}
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
</Tbody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Box>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
<Flex
|
||||
direction={{ base: 'column', lg: 'row' }}
|
||||
gap={4}
|
||||
>
|
||||
{/* 左侧:饼图 */}
|
||||
<Box
|
||||
flexShrink={0}
|
||||
w={{ base: '100%', lg: '340px' }}
|
||||
bg={THEME.cardBg}
|
||||
border="1px solid"
|
||||
borderColor={THEME.border}
|
||||
borderRadius="md"
|
||||
p={4}
|
||||
>
|
||||
<ReactECharts option={pieOption} style={{ height: '280px' }} />
|
||||
</Box>
|
||||
|
||||
{/* 历史对比 - Ant Design Table 黑金主题 */}
|
||||
{historicalData.length > 1 && (
|
||||
<HistoricalComparisonTable
|
||||
historicalData={historicalData}
|
||||
businessItems={businessItems}
|
||||
hasProductData={hasProductData}
|
||||
/>
|
||||
)}
|
||||
</VStack>
|
||||
{/* 右侧:业务明细与历史对比表格 */}
|
||||
<Box flex={1} minW={0} overflow="hidden">
|
||||
{historicalData.length > 0 && (
|
||||
<HistoricalComparisonTable
|
||||
historicalData={historicalData}
|
||||
businessItems={businessItems}
|
||||
hasProductData={hasProductData}
|
||||
latestReportType={latestPeriod.report_type}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user