From 5a3888d90562b2818f0ea37b53dfad3a0c837daa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Wed, 25 Feb 2026 15:41:23 +0800 Subject: [PATCH] =?UTF-8?q?fix(trade=5Fquery):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E7=AD=9B=E9=80=89=E9=80=BB=E8=BE=91=E4=BB=A5?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=88=9B=E5=BB=BA=E6=97=B6=E9=97=B4=E7=9A=84?= =?UTF-8?q?=E5=9B=9E=E9=80=80=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在交易查询逻辑中,调整了时间筛选条件,确保在存在 `created_at` 列时使用 `COALESCE(created_at, entry_time)`,并在无该列时回退至 `entry_time`。同时,增强了对时间筛选的支持,确保在不同筛选条件下均能正确返回结果。这一改动旨在提升查询的准确性与一致性。 --- backend/database/models.py | 19 ++++++++++++------- frontend/src/components/StatsDashboard.css | 8 ++++++++ frontend/src/components/StatsDashboard.jsx | 13 +++++-------- frontend/src/components/TradeList.jsx | 2 +- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/backend/database/models.py b/backend/database/models.py index 761f9fd..c8bbb61 100644 --- a/backend/database/models.py +++ b/backend/database/models.py @@ -1104,7 +1104,7 @@ class Trade: query += " AND (entry_reason IS NULL OR entry_reason != 'sync_recovered')" 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")) time_col = "COALESCE(created_at, entry_time)" if use_created else None @@ -1118,6 +1118,9 @@ class Trade: elif use_created: query += " AND " + time_col + " >= %s AND " + time_col + " <= %s" 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: query += " AND COALESCE(exit_time, entry_time) >= %s AND COALESCE(exit_time, entry_time) <= %s" params.extend([start_timestamp, end_timestamp]) @@ -1125,12 +1128,12 @@ class Trade: if time_filter == "exit": query += " AND ((status = 'closed' AND exit_time >= %s) OR (status != 'closed' AND entry_time >= %s))" params.extend([start_timestamp, start_timestamp]) - elif time_filter == "entry": - query += " AND entry_time >= %s" - params.append(start_timestamp) elif use_created: query += " AND " + time_col + " >= %s" params.append(start_timestamp) + elif time_filter == "entry" or time_filter == "created": + query += " AND entry_time >= %s" + params.append(start_timestamp) else: query += " AND COALESCE(exit_time, entry_time) >= %s" params.append(start_timestamp) @@ -1138,12 +1141,12 @@ class Trade: if time_filter == "exit": query += " AND ((status = 'closed' AND exit_time <= %s) OR (status != 'closed' AND entry_time <= %s))" params.extend([end_timestamp, end_timestamp]) - elif time_filter == "entry": - query += " AND entry_time <= %s" - params.append(end_timestamp) elif use_created: query += " AND " + time_col + " <= %s" params.append(end_timestamp) + elif time_filter == "entry" or time_filter == "created": + query += " AND entry_time <= %s" + params.append(end_timestamp) else: query += " AND COALESCE(exit_time, entry_time) <= %s" params.append(end_timestamp) @@ -1163,6 +1166,8 @@ class Trade: if use_created: query += " ORDER BY " + time_col + " DESC, id DESC" + elif time_filter == "created": + query += " ORDER BY entry_time DESC, id DESC" else: query += " ORDER BY COALESCE(exit_time, entry_time) DESC, id DESC" # 未传 limit 时使用默认上限,防止全表加载导致内存暴增(2 CPU 4G 场景) diff --git a/frontend/src/components/StatsDashboard.css b/frontend/src/components/StatsDashboard.css index b0cad95..939b4d9 100644 --- a/frontend/src/components/StatsDashboard.css +++ b/frontend/src/components/StatsDashboard.css @@ -339,6 +339,14 @@ 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 { color: #999; font-size: 0.8rem; diff --git a/frontend/src/components/StatsDashboard.jsx b/frontend/src/components/StatsDashboard.jsx index 8f84a6c..60771e8 100644 --- a/frontend/src/components/StatsDashboard.jsx +++ b/frontend/src/components/StatsDashboard.jsx @@ -696,6 +696,11 @@ const StatsDashboard = () => { {trade.side}
+
+ 开仓时间: {(trade.entry_time || trade.created_at) ? formatEntryTime(trade.entry_time || trade.created_at) : '—'} + {' · '} + 创建时间: {(trade.created_at != null && trade.created_at !== '') ? formatEntryTime(trade.created_at) : '—'} +
入场类型:{' '} {
{/* 止损止盈比例 */} - - -
- 开仓时间: {(trade.entry_time || trade.created_at) ? formatEntryTime(trade.entry_time || trade.created_at) : '—'} -
-
- 创建时间: {(trade.created_at != null && trade.created_at !== '') ? formatEntryTime(trade.created_at) : '—'} -
diff --git a/frontend/src/components/TradeList.jsx b/frontend/src/components/TradeList.jsx index 302bd75..590f6df 100644 --- a/frontend/src/components/TradeList.jsx +++ b/frontend/src/components/TradeList.jsx @@ -29,7 +29,7 @@ const TradeList = () => { useEffect(() => { loadData() - }, [accountId, reconciledOnly, timeFilter]) // accountId / 仅可对账 / 时间筛选方式 变化时重新加载 + }, [accountId, reconciledOnly, timeFilter, period, useCustomDate, startDate, endDate, symbol, status, tradeType, exitReason]) // 筛选条件变化时重新加载(含按创建时间、快速时间段) const loadData = async () => { setLoading(true)