"use client" import { useEffect, useState } from "react" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table" import { Loader2, TrendingUp, TrendingDown, DollarSign } from "lucide-react" import { getFinancialData } from "@/lib/api" import { formatNumber, formatLargeNumber, formatDate } from "@/lib/formatters" import type { FinancialDataResponse } from "@/lib/types" interface FinancialTablesProps { companyId: number dataSource: string } export function FinancialTables({ companyId, dataSource }: FinancialTablesProps) { const [data, setData] = useState(null) const [loading, setLoading] = useState(true) const [error, setError] = useState("") useEffect(() => { async function loadData() { setLoading(true) setError("") try { const result = await getFinancialData(companyId, dataSource) setData(result) } catch (err: any) { setError(err.message || "加载财务数据失败") } finally { setLoading(false) } } loadData() }, [companyId, dataSource]) if (loading) { return ( ) } if (error) { return (
{error}
) } if (!data) { return null } const isBloomberg = dataSource === 'Bloomberg' const TableComponent = isBloomberg ? TransposedFinancialTable : FinancialTable return ( 财务数据

利润表

资产负债表

现金流量表

估值数据

) } interface FinancialTableProps { data: Record[] title: string icon?: React.ReactNode } function FinancialTable({ data, title }: FinancialTableProps) { if (!data || data.length === 0) { return (
暂无{title}数据
) } // 获取所有列名(排除 id, code, ticker, market, update_date 等元数据列) const excludeColumns = ['id', 'code', 'ticker', 'market', 'update_date', 'ts_code'] const columns = Object.keys(data[0]).filter(key => !excludeColumns.includes(key)) return (
{columns.map((column) => ( {formatColumnName(column)} ))} {data.map((row, idx) => ( {columns.map((column) => ( {formatCellValue(column, row[column])} ))} ))}
共 {data.length} 条记录
) } function TransposedFinancialTable({ data, title }: FinancialTableProps) { if (!data || data.length === 0) { return (
暂无{title}数据
) } // 1. 提取所有日期 (Headers) // 假设 data 是按时间倒序排列的 (API通常如此) // 如果不是,建议在这里做个sort const sortedData = [...data].sort((a, b) => new Date(b.end_date).getTime() - new Date(a.end_date).getTime() ) const dates = sortedData.map(row => row['end_date']).filter(Boolean) // 2. 提取所有指标 (Rows) const excludeColumns = ['id', 'code', 'ticker', 'market', 'update_date', 'ts_code', 'end_date'] // 从第一行获取所有指标key const indicators = Object.keys(sortedData[0]).filter(key => !excludeColumns.includes(key)) return (
{/* 第一列:指标名称 */} 指标 / 报告期 {/* 其他列:日期 */} {dates.map((date, idx) => ( {formatDate(date)} ))} {indicators.map((indicator) => ( {/* 指标名 */} {formatColumnName(indicator)} {/* 值 */} {sortedData.map((row, rowIdx) => ( {formatCellValue(indicator, row[indicator])} ))} ))}
共 {indicators.length} 个指标
) } // 格式化列名 function formatColumnName(column: string): string { const nameMap: Record = { 'end_date': '报告期', // Common 'revenue': '营业收入', 'net_income': '净利润', // Balance Sheet 'total_assets': '总资产', 'total_liabilities': '总负债', 'total_equity': '股东权益', 'cash': '货币资金', 'inventory': '存货', 'receivables': '应收账款', 'prepayment': '预付款项', 'fixed_assets': '固定资产', 'long_term_investments': '长期投资', 'accounts_payable': '应付账款', 'short_term_debt': '短期借款', 'long_term_debt': '长期借款', 'deferred_revenue': '递延收入', 'goodwill': '商誉', // Income 'sga_exp': '销售管理费用', 'selling_marketing_exp': '销售费用', 'ga_exp': '管理费用', 'rd_exp': '研发费用', 'depreciation': '折旧', 'operating_profit': '营业利润', // Cash Flow 'ocf': '经营现金流', 'capex': '资本支出', 'dividends': '分红支付', 'fcf': '自由现金流', // Metrics 'pe': '市盈率(PE)', 'pb': '市净率(PB)', 'market_cap': '市值', 'price': '最新股价', 'roe': 'ROE', 'roa': 'ROA', } return nameMap[column] || column } // 格式化单元格值 function formatCellValue(column: string, value: any): string { if (value === null || value === undefined) { return '-' } // 日期列 if (column.includes('date')) { return formatDate(value) } // 数值列 if (typeof value === 'number') { // 比率和百分比(PE、PB等) if (column.includes('ratio') || column.includes('pe') || column.includes('pb') || column.includes('margin') || column.includes('roe') || column.includes('roa') || column.includes('rate')) { return formatNumber(value) } // 大数字(金额、市值等) return formatLargeNumber(value) } return String(value) }