diff --git a/frontend/components/dashboard/scan-terminal/KoyfinRowsTable.tsx b/frontend/components/dashboard/scan-terminal/KoyfinRowsTable.tsx new file mode 100644 index 00000000..9732eed7 --- /dev/null +++ b/frontend/components/dashboard/scan-terminal/KoyfinRowsTable.tsx @@ -0,0 +1,93 @@ +"use client"; + +import clsx from "clsx"; +import type { ScanOpportunityRow } from "@/lib/dashboard-types"; +import { formatPrice } from "@/components/dashboard/scan-terminal/continent-grouping"; +import { rowName, pct } from "@/components/dashboard/scan-terminal/utils"; + +function tablePrice(row: ScanOpportunityRow) { + return formatPrice(row.midpoint, row.ask, row.bid); +} + +export function KoyfinRowsTable({ + compact = false, + isEn, + onSelect, + rows, + selectedId, +}: { + compact?: boolean; + isEn: boolean; + onSelect: (row: ScanOpportunityRow) => void; + rows: ScanOpportunityRow[]; + selectedId?: string | null; +}) { + return ( + + + + + + + + + + + + {rows.map((row) => { + const edge = Number(row.edge_percent ?? row.signed_gap ?? row.gap ?? 0); + const positive = edge >= 0; + return ( + onSelect(row)} + className={clsx( + "cursor-pointer border-b border-slate-100 hover:bg-blue-50/70", + selectedId === row.id && "bg-blue-50", + )} + > + + + + + + + ); + })} + +
+ + + {isEn ? "City" : "城市"} + + {isEn ? "Price" : "价格"} + + {isEn ? "Chg" : "变化"} + %
+ + +
+ {rowName(row)} +
+
+ {row.target_label || row.market_question || row.airport || "--"} +
+
+ {tablePrice(row)} + + {Number.isFinite(edge) ? `${positive ? "+" : ""}${edge.toFixed(1)}` : "--"} + + {pct(row.market_probability ?? row.market_event_probability ?? row.model_probability)} +
+ ); +}