- 创建 MarketDataSkeleton 组件(摘要卡片 + K线图表 + Tab) - 配置 Suspense fallback,点击时直接显示骨架屏 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
127 lines
3.6 KiB
TypeScript
127 lines
3.6 KiB
TypeScript
/**
|
||
* 财务表格共享主题配置
|
||
*
|
||
* 用于统一 BalanceSheetTable、IncomeStatementTable、CashflowTable 等表格组件的主题样式
|
||
*/
|
||
|
||
import type { ThemeConfig } from 'antd';
|
||
|
||
/** Ant Design 黑金主题配置 */
|
||
export const BLACK_GOLD_TABLE_THEME: ThemeConfig = {
|
||
token: {
|
||
colorBgContainer: 'transparent',
|
||
colorText: '#E2E8F0',
|
||
colorTextHeading: '#D4AF37',
|
||
colorBorderSecondary: 'rgba(212, 175, 55, 0.2)',
|
||
},
|
||
components: {
|
||
Table: {
|
||
headerBg: 'rgba(26, 32, 44, 0.8)',
|
||
headerColor: '#D4AF37',
|
||
rowHoverBg: 'rgba(212, 175, 55, 0.1)',
|
||
borderColor: 'rgba(212, 175, 55, 0.15)',
|
||
cellPaddingBlock: 6,
|
||
cellPaddingInline: 8,
|
||
// 表头紧凑样式
|
||
headerSplitColor: 'transparent',
|
||
},
|
||
},
|
||
};
|
||
|
||
/**
|
||
* 生成表格样式 CSS
|
||
* @param className 表格容器的 className
|
||
*/
|
||
export const getTableStyles = (className: string): string => `
|
||
.${className} .ant-table {
|
||
background: transparent !important;
|
||
}
|
||
.${className} .ant-table-thead > tr > th {
|
||
background: rgba(26, 32, 44, 0.8) !important;
|
||
color: #D4AF37 !important;
|
||
border-bottom: 1px solid rgba(212, 175, 55, 0.3) !important;
|
||
font-weight: 600;
|
||
font-size: 13px;
|
||
padding: 4px 8px !important;
|
||
margin: 0 !important;
|
||
}
|
||
.${className} .ant-table-thead > tr {
|
||
margin: 0 !important;
|
||
}
|
||
.${className} .ant-table-header {
|
||
margin: 0 !important;
|
||
padding: 0 !important;
|
||
}
|
||
.${className} .ant-table-tbody > tr > td {
|
||
border-bottom: 1px solid rgba(212, 175, 55, 0.1) !important;
|
||
color: #E2E8F0;
|
||
font-size: 12px;
|
||
}
|
||
.${className} .ant-table-tbody > tr:hover > td {
|
||
background: rgba(212, 175, 55, 0.08) !important;
|
||
}
|
||
.${className} .ant-table-tbody > tr.total-row > td {
|
||
background: rgba(212, 175, 55, 0.15) !important;
|
||
font-weight: 600;
|
||
}
|
||
.${className} .ant-table-tbody > tr.section-header > td {
|
||
background: rgba(212, 175, 55, 0.08) !important;
|
||
font-weight: 600;
|
||
color: #D4AF37;
|
||
}
|
||
.${className} .ant-table-cell-fix-left,
|
||
.${className} .ant-table-cell-fix-right {
|
||
background: #1A202C !important;
|
||
}
|
||
.${className} .ant-table-tbody > tr:hover .ant-table-cell-fix-left,
|
||
.${className} .ant-table-tbody > tr:hover .ant-table-cell-fix-right {
|
||
background: rgba(26, 32, 44, 0.95) !important;
|
||
}
|
||
.${className} .positive-change {
|
||
color: #E53E3E;
|
||
}
|
||
.${className} .negative-change {
|
||
color: #48BB78;
|
||
}
|
||
.${className} .ant-table-placeholder {
|
||
background: transparent !important;
|
||
}
|
||
.${className} .ant-empty-description {
|
||
color: #A0AEC0;
|
||
}
|
||
`;
|
||
|
||
/**
|
||
* 计算同比变化(YoY)
|
||
* @param data 数据数组
|
||
* @param currentValue 当前值
|
||
* @param currentPeriod 当前期间
|
||
* @param path 数据路径
|
||
* @param getValueByPath 获取路径值的函数
|
||
*/
|
||
export const calculateYoY = <T extends { period: string }>(
|
||
data: T[],
|
||
currentValue: number | undefined,
|
||
currentPeriod: string,
|
||
path: string,
|
||
getValueByPath: (item: T, path: string) => number | undefined
|
||
): number | null => {
|
||
if (currentValue === undefined || currentValue === null) return null;
|
||
|
||
const currentDate = new Date(currentPeriod);
|
||
const lastYearPeriod = data.find((item) => {
|
||
const date = new Date(item.period);
|
||
return (
|
||
date.getFullYear() === currentDate.getFullYear() - 1 &&
|
||
date.getMonth() === currentDate.getMonth()
|
||
);
|
||
});
|
||
|
||
if (!lastYearPeriod) return null;
|
||
|
||
const lastYearValue = getValueByPath(lastYearPeriod, path);
|
||
if (lastYearValue === undefined || lastYearValue === 0) return null;
|
||
|
||
return ((currentValue - lastYearValue) / Math.abs(lastYearValue)) * 100;
|
||
};
|