fix: db migration tab char corrupted, restore historical trades

This commit is contained in:
jackyu66git
2026-05-04 13:50:49 +08:00
parent e74fd084ce
commit f29e78a435
5 changed files with 264 additions and 58 deletions
+78 -28
View File
@@ -198,6 +198,13 @@ function StatsCard({ stats }) {
connHtml = Object.entries(stats.connections)
.map(([ex, status]) => `${ex}:${status}`).join(' ')
}
// Format exchange funds
let exFundsHtml = ''
if (stats.exchange_funds) {
exFundsHtml = Object.entries(stats.exchange_funds)
.map(([ex, f]) => `${ex}: $${f.balance.toFixed(2)}`)
.join(' | ')
}
return (
<section className="card" id="stats-card">
<h2>📊 统计数据</h2>
@@ -210,6 +217,11 @@ function StatsCard({ stats }) {
<div className="stat"><label>币种</label><span className="pct-blue">{stats.coins || 0}</span></div>
<div className="stat" id="conn-stats"><label>连接</label><span id="conn-detail" style={{fontSize:11}}>{connHtml}</span></div>
</div>
{exFundsHtml && (
<div className="stats-row" style={{ marginTop: 2, fontSize: 11, opacity: 0.85 }}>
<div className="stat" style={{gridColumn:'1 / -1'}}><label>资金</label><span style={{fontWeight:600}}>{exFundsHtml}</span></div>
</div>
)}
{d && (
<div className="stats-row detail-stats" style={{ marginTop: 4, fontSize: 12, opacity: 0.85 }}>
<div className="stat"><label>总PnL</label><span>{(d.total_pnl_usd != null ? '$' + d.total_pnl_usd.toFixed(2) : '—') + (d.capital_pnl != null ? ' (' + d.capital_pnl.toFixed(4) + '%)' : '')}</span></div>
@@ -225,35 +237,73 @@ function StatsCard({ stats }) {
}
function PositionsCard({ positions }) {
const [modalOpen, setModalOpen] = useState(false)
const [modalTrade, setModalTrade] = useState(null)
const [modalOrders, setModalOrders] = useState([])
function openPositionDetail(id) {
if (!id) return
setModalOpen(true)
setModalTrade(null)
setModalOrders([])
fetch('/api/trade/' + id)
.then(r => r.json())
.then(data => {
setModalTrade(data.trade)
setModalOrders(data.orders || [])
})
.catch(() => {
setModalTrade({ ID: id })
})
}
function closeModal() {
setModalOpen(false)
}
useEffect(() => {
if (!modalOpen) return
function handler(e) {
if (e.key === 'Escape') closeModal()
}
document.addEventListener('keydown', handler)
return () => document.removeEventListener('keydown', handler)
}, [modalOpen])
return (
<section className="card" id="positions-card">
<h2>🔒 当前持仓</h2>
<div className="table-wrap">
<table id="positions-table">
<thead>
<tr><th>币种</th><th>方向</th><th>规模</th><th>入价差</th><th>现价差</th><th>估盈亏</th><th>加仓</th><th>时长</th></tr>
</thead>
<tbody id="positions-body">
{positions.length === 0 ? (
<tr><td colSpan="8" className="loading">无持仓</td></tr>
) : (
[...positions].sort((a, b) => a.coin.localeCompare(b.coin)).map(p => (
<tr key={p.coin}>
<td><strong>{p.coin}</strong></td>
<td>{p.direction}</td>
<td className="text-right">${(p.amount_usd || 0).toFixed(0)}</td>
<td className="text-right">{(p.entry_spread || 0).toFixed(4)}%</td>
<td className="text-right">{p.current_spread != null ? p.current_spread.toFixed(4) + '%' : '-'}</td>
<td className={'text-right ' + pnlClass(p.pnl_est)}><strong>{p.pnl_est != null ? '$' + p.pnl_est.toFixed(4) : '-'}</strong></td>
<td className="text-right">{p.scales || 0}</td>
<td>{p.duration || '-'}</td>
</tr>
))
)}
</tbody>
</table>
</div>
</section>
<>
<section className="card" id="positions-card">
<h2>🔒 当前持仓</h2>
<div className="table-wrap">
<table id="positions-table">
<thead>
<tr><th>币种</th><th>方向</th><th>规模</th><th>入价差</th><th>现价差</th><th>估盈亏</th><th>加仓</th><th>时长</th></tr>
</thead>
<tbody id="positions-body">
{positions.length === 0 ? (
<tr><td colSpan="8" className="loading">无持仓</td></tr>
) : (
[...positions].sort((a, b) => a.coin.localeCompare(b.coin)).map(p => (
<tr key={p.coin} className="trade-row" onClick={() => openPositionDetail(p.db_trade_id)}>
<td><strong>{p.coin}</strong></td>
<td>{p.direction}</td>
<td className="text-right">${(p.amount_usd || 0).toFixed(0)}</td>
<td className="text-right">{(p.entry_spread || 0).toFixed(4)}%</td>
<td className="text-right">{p.current_spread != null ? p.current_spread.toFixed(4) + '%' : '-'}</td>
<td className={'text-right ' + pnlClass(p.pnl_est)}><strong>{p.pnl_est != null ? '$' + p.pnl_est.toFixed(4) : '-'}</strong></td>
<td className="text-right">{p.scales || 0}</td>
<td>{p.duration || '-'}</td>
</tr>
))
)}
</tbody>
</table>
</div>
</section>
{modalOpen && (
<TradeDetailModal trade={modalTrade} orders={modalOrders} onClose={closeModal} />
)}
</>
)
}