From 7b58f834907d584b36a585746071f6427767dcab Mon Sep 17 00:00:00 2001 From: zdl <3489966805@qq.com> Date: Fri, 19 Dec 2025 14:44:13 +0800 Subject: [PATCH] =?UTF-8?q?refactor(FinancialPanorama):=20=E6=8F=90?= =?UTF-8?q?=E5=8F=96=E5=85=B1=E4=BA=AB=E8=A1=A8=E6=A0=BC=E4=B8=BB=E9=A2=98?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 utils/tableTheme.ts 统一黑金主题配置 - BLACK_GOLD_TABLE_THEME: Ant Design ConfigProvider 主题 - getTableStyles(): CSS 样式工厂函数 - calculateYoY(): 同比计算共享函数 - 消除约 200 行重复代码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../FinancialPanorama/utils/index.ts | 6 + .../FinancialPanorama/utils/tableTheme.ts | 115 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 src/views/Company/components/FinancialPanorama/utils/tableTheme.ts diff --git a/src/views/Company/components/FinancialPanorama/utils/index.ts b/src/views/Company/components/FinancialPanorama/utils/index.ts index fd302b02..1c8fdc35 100644 --- a/src/views/Company/components/FinancialPanorama/utils/index.ts +++ b/src/views/Company/components/FinancialPanorama/utils/index.ts @@ -15,3 +15,9 @@ export { getMainBusinessPieOption, getCompareBarChartOption, } from './chartOptions'; + +export { + BLACK_GOLD_TABLE_THEME, + getTableStyles, + calculateYoY, +} from './tableTheme'; diff --git a/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts b/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts new file mode 100644 index 00000000..e1e8adbd --- /dev/null +++ b/src/views/Company/components/FinancialPanorama/utils/tableTheme.ts @@ -0,0 +1,115 @@ +/** + * 财务表格共享主题配置 + * + * 用于统一 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: 8, + cellPaddingInline: 12, + }, + }, +}; + +/** + * 生成表格样式 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; + } + .${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 = ( + 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; +};