fix(trade_query): 优化时间筛选逻辑以支持创建时间的回退处理

在交易查询逻辑中,调整了时间筛选条件,确保在存在 `created_at` 列时使用 `COALESCE(created_at, entry_time)`,并在无该列时回退至 `entry_time`。同时,增强了对时间筛选的支持,确保在不同筛选条件下均能正确返回结果。这一改动旨在提升查询的准确性与一致性。
This commit is contained in:
薇薇安 2026-02-25 15:41:23 +08:00
parent 5c854290eb
commit 5a3888d905
4 changed files with 26 additions and 16 deletions

View File

@ -1104,7 +1104,7 @@ class Trade:
query += " AND (entry_reason IS NULL OR entry_reason != 'sync_recovered')" query += " AND (entry_reason IS NULL OR entry_reason != 'sync_recovered')"
query += " AND (exit_reason IS NULL OR exit_reason != 'sync')" query += " AND (exit_reason IS NULL OR exit_reason != 'sync')"
# 按创建时间筛选时若表无 created_at 则回退为 entry_time # 按创建时间筛选:有 created_at 列则用 COALESCE(created_at, entry_time);无则回退为 entry_time保证「按创建时间」有结果
use_created = (time_filter == "created" and _table_has_column("trades", "created_at")) use_created = (time_filter == "created" and _table_has_column("trades", "created_at"))
time_col = "COALESCE(created_at, entry_time)" if use_created else None time_col = "COALESCE(created_at, entry_time)" if use_created else None
@ -1118,6 +1118,9 @@ class Trade:
elif use_created: elif use_created:
query += " AND " + time_col + " >= %s AND " + time_col + " <= %s" query += " AND " + time_col + " >= %s AND " + time_col + " <= %s"
params.extend([start_timestamp, end_timestamp]) params.extend([start_timestamp, end_timestamp])
elif time_filter == "created":
query += " AND entry_time >= %s AND entry_time <= %s"
params.extend([start_timestamp, end_timestamp])
else: else:
query += " AND COALESCE(exit_time, entry_time) >= %s AND COALESCE(exit_time, entry_time) <= %s" query += " AND COALESCE(exit_time, entry_time) >= %s AND COALESCE(exit_time, entry_time) <= %s"
params.extend([start_timestamp, end_timestamp]) params.extend([start_timestamp, end_timestamp])
@ -1125,12 +1128,12 @@ class Trade:
if time_filter == "exit": if time_filter == "exit":
query += " AND ((status = 'closed' AND exit_time >= %s) OR (status != 'closed' AND entry_time >= %s))" query += " AND ((status = 'closed' AND exit_time >= %s) OR (status != 'closed' AND entry_time >= %s))"
params.extend([start_timestamp, start_timestamp]) params.extend([start_timestamp, start_timestamp])
elif time_filter == "entry":
query += " AND entry_time >= %s"
params.append(start_timestamp)
elif use_created: elif use_created:
query += " AND " + time_col + " >= %s" query += " AND " + time_col + " >= %s"
params.append(start_timestamp) params.append(start_timestamp)
elif time_filter == "entry" or time_filter == "created":
query += " AND entry_time >= %s"
params.append(start_timestamp)
else: else:
query += " AND COALESCE(exit_time, entry_time) >= %s" query += " AND COALESCE(exit_time, entry_time) >= %s"
params.append(start_timestamp) params.append(start_timestamp)
@ -1138,12 +1141,12 @@ class Trade:
if time_filter == "exit": if time_filter == "exit":
query += " AND ((status = 'closed' AND exit_time <= %s) OR (status != 'closed' AND entry_time <= %s))" query += " AND ((status = 'closed' AND exit_time <= %s) OR (status != 'closed' AND entry_time <= %s))"
params.extend([end_timestamp, end_timestamp]) params.extend([end_timestamp, end_timestamp])
elif time_filter == "entry":
query += " AND entry_time <= %s"
params.append(end_timestamp)
elif use_created: elif use_created:
query += " AND " + time_col + " <= %s" query += " AND " + time_col + " <= %s"
params.append(end_timestamp) params.append(end_timestamp)
elif time_filter == "entry" or time_filter == "created":
query += " AND entry_time <= %s"
params.append(end_timestamp)
else: else:
query += " AND COALESCE(exit_time, entry_time) <= %s" query += " AND COALESCE(exit_time, entry_time) <= %s"
params.append(end_timestamp) params.append(end_timestamp)
@ -1163,6 +1166,8 @@ class Trade:
if use_created: if use_created:
query += " ORDER BY " + time_col + " DESC, id DESC" query += " ORDER BY " + time_col + " DESC, id DESC"
elif time_filter == "created":
query += " ORDER BY entry_time DESC, id DESC"
else: else:
query += " ORDER BY COALESCE(exit_time, entry_time) DESC, id DESC" query += " ORDER BY COALESCE(exit_time, entry_time) DESC, id DESC"
# 未传 limit 时使用默认上限防止全表加载导致内存暴增2 CPU 4G 场景) # 未传 limit 时使用默认上限防止全表加载导致内存暴增2 CPU 4G 场景)

View File

@ -339,6 +339,14 @@
border-radius: 6px; border-radius: 6px;
} }
.position-time-row {
font-size: 0.85rem;
color: #212529;
margin-bottom: 0.5rem;
font-weight: 500;
}
.position-time-row:empty { display: none; }
.entry-time { .entry-time {
color: #999; color: #999;
font-size: 0.8rem; font-size: 0.8rem;

View File

@ -696,6 +696,11 @@ const StatsDashboard = () => {
{trade.side} {trade.side}
</div> </div>
<div className="trade-info"> <div className="trade-info">
<div className="position-time-row">
开仓时间: {(trade.entry_time || trade.created_at) ? formatEntryTime(trade.entry_time || trade.created_at) : '—'}
{' · '}
创建时间: {(trade.created_at != null && trade.created_at !== '') ? formatEntryTime(trade.created_at) : '—'}
</div>
<div className="entry-type-line"> <div className="entry-type-line">
入场类型:{' '} 入场类型:{' '}
<span <span
@ -736,14 +741,6 @@ const StatsDashboard = () => {
</div> </div>
{/* 止损止盈比例 */} {/* 止损止盈比例 */}
<div className="entry-time">
开仓时间: {(trade.entry_time || trade.created_at) ? formatEntryTime(trade.entry_time || trade.created_at) : '—'}
</div>
<div className="entry-time">
创建时间: {(trade.created_at != null && trade.created_at !== '') ? formatEntryTime(trade.created_at) : '—'}
</div>
</div> </div>
<div className="trade-protection-col"> <div className="trade-protection-col">
<div className="stop-take-info"> <div className="stop-take-info">

View File

@ -29,7 +29,7 @@ const TradeList = () => {
useEffect(() => { useEffect(() => {
loadData() loadData()
}, [accountId, reconciledOnly, timeFilter]) // accountId / 仅可对账 / 时间筛选方式 变化时重新加载 }, [accountId, reconciledOnly, timeFilter, period, useCustomDate, startDate, endDate, symbol, status, tradeType, exitReason]) //
const loadData = async () => { const loadData = async () => {
setLoading(true) setLoading(true)