Show total pages and card-local AJAX paging on options review.
Trades and reviewed lists now report page X / Y and flip without full-page sync refresh. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -591,8 +591,7 @@ def enrich_trade_row(row: dict[str, Any], entry: dict[str, Any] | None = None) -
|
||||
return out
|
||||
|
||||
|
||||
def list_review_trades(
|
||||
conn: sqlite3.Connection,
|
||||
def _review_trades_filters(
|
||||
*,
|
||||
source_type: str | None = None,
|
||||
underlying: str | None = None,
|
||||
@@ -602,10 +601,7 @@ def list_review_trades(
|
||||
include_hedge_legs: bool = False,
|
||||
closed_from: str | None = None,
|
||||
closed_to: str | None = None,
|
||||
limit: int = 200,
|
||||
offset: int = 0,
|
||||
) -> list[dict[str, Any]]:
|
||||
init_options_review_tables(conn)
|
||||
) -> tuple[str, list[Any]]:
|
||||
wheres: list[str] = []
|
||||
args: list[Any] = []
|
||||
if source_type and source_type in SOURCE_TYPES:
|
||||
@@ -647,6 +643,69 @@ def list_review_trades(
|
||||
elif reviewed == "0" or reviewed == "no":
|
||||
wheres.append("e.id IS NULL")
|
||||
where = (" WHERE " + " AND ".join(wheres)) if wheres else ""
|
||||
return where, args
|
||||
|
||||
|
||||
def count_review_trades(
|
||||
conn: sqlite3.Connection,
|
||||
*,
|
||||
source_type: str | None = None,
|
||||
underlying: str | None = None,
|
||||
opt_type: str | None = None,
|
||||
strategy_tag: str | None = None,
|
||||
reviewed: str | None = None,
|
||||
include_hedge_legs: bool = False,
|
||||
closed_from: str | None = None,
|
||||
closed_to: str | None = None,
|
||||
) -> int:
|
||||
init_options_review_tables(conn)
|
||||
where, args = _review_trades_filters(
|
||||
source_type=source_type,
|
||||
underlying=underlying,
|
||||
opt_type=opt_type,
|
||||
strategy_tag=strategy_tag,
|
||||
reviewed=reviewed,
|
||||
include_hedge_legs=include_hedge_legs,
|
||||
closed_from=closed_from,
|
||||
closed_to=closed_to,
|
||||
)
|
||||
row = conn.execute(
|
||||
f"""
|
||||
SELECT COUNT(*) AS c
|
||||
FROM options_review_trades t
|
||||
LEFT JOIN options_review_entries e ON e.trade_id = t.id
|
||||
{where}
|
||||
""",
|
||||
args,
|
||||
).fetchone()
|
||||
return int(row["c"] if row else 0)
|
||||
|
||||
|
||||
def list_review_trades(
|
||||
conn: sqlite3.Connection,
|
||||
*,
|
||||
source_type: str | None = None,
|
||||
underlying: str | None = None,
|
||||
opt_type: str | None = None,
|
||||
strategy_tag: str | None = None,
|
||||
reviewed: str | None = None,
|
||||
include_hedge_legs: bool = False,
|
||||
closed_from: str | None = None,
|
||||
closed_to: str | None = None,
|
||||
limit: int = 200,
|
||||
offset: int = 0,
|
||||
) -> list[dict[str, Any]]:
|
||||
init_options_review_tables(conn)
|
||||
where, args = _review_trades_filters(
|
||||
source_type=source_type,
|
||||
underlying=underlying,
|
||||
opt_type=opt_type,
|
||||
strategy_tag=strategy_tag,
|
||||
reviewed=reviewed,
|
||||
include_hedge_legs=include_hedge_legs,
|
||||
closed_from=closed_from,
|
||||
closed_to=closed_to,
|
||||
)
|
||||
rows = conn.execute(
|
||||
f"""
|
||||
SELECT t.*, e.id AS entry_id, e.strategy_tag AS e_strategy_tag,
|
||||
|
||||
@@ -19,6 +19,7 @@ from lib.options.options_review_images_lib import (
|
||||
from lib.options.options_review_lib import (
|
||||
SOURCE_LABELS,
|
||||
compute_review_stats,
|
||||
count_review_trades,
|
||||
delete_review_entry,
|
||||
ensure_local_review_synced,
|
||||
get_review_trade,
|
||||
@@ -120,23 +121,46 @@ def register_options_review_routes(app: Flask, cfg: dict[str, Any], repo_root: s
|
||||
def api_options_review_trades():
|
||||
conn = cfg["get_db"]()
|
||||
try:
|
||||
ensure_local_review_synced(conn)
|
||||
conn.commit()
|
||||
items = list_review_trades(
|
||||
conn,
|
||||
# 翻页可跳过同步,仅刷新当前卡片列表
|
||||
do_sync = (request.args.get("sync") or "1").strip().lower() not in (
|
||||
"0",
|
||||
"false",
|
||||
"no",
|
||||
)
|
||||
if do_sync:
|
||||
ensure_local_review_synced(conn)
|
||||
conn.commit()
|
||||
filt = dict(
|
||||
source_type=(request.args.get("source_type") or "").strip() or None,
|
||||
underlying=(request.args.get("underlying") or "").strip() or None,
|
||||
opt_type=(request.args.get("opt_type") or "").strip() or None,
|
||||
strategy_tag=(request.args.get("strategy_tag") or "").strip() or None,
|
||||
reviewed=(request.args.get("reviewed") or "").strip() or None,
|
||||
include_hedge_legs=(request.args.get("include_hedge_legs") or "").strip().lower()
|
||||
include_hedge_legs=(request.args.get("include_hedge_legs") or "")
|
||||
.strip()
|
||||
.lower()
|
||||
in ("1", "true", "yes"),
|
||||
closed_from=(request.args.get("closed_from") or "").strip() or None,
|
||||
closed_to=(request.args.get("closed_to") or "").strip() or None,
|
||||
limit=min(500, max(1, int(request.args.get("limit") or 200))),
|
||||
offset=max(0, int(request.args.get("offset") or 0)),
|
||||
)
|
||||
return jsonify({"ok": True, "trades": items, "source_labels": SOURCE_LABELS})
|
||||
limit = min(500, max(1, int(request.args.get("limit") or 200)))
|
||||
offset = max(0, int(request.args.get("offset") or 0))
|
||||
total = count_review_trades(conn, **filt)
|
||||
items = list_review_trades(conn, **filt, limit=limit, offset=offset)
|
||||
pages = max(1, (total + limit - 1) // limit) if total else 1
|
||||
page = (offset // limit) + 1 if limit else 1
|
||||
return jsonify(
|
||||
{
|
||||
"ok": True,
|
||||
"trades": items,
|
||||
"source_labels": SOURCE_LABELS,
|
||||
"total": total,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
"page": page,
|
||||
"pages": pages,
|
||||
}
|
||||
)
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
</div>
|
||||
<div class="or-pager" id="or-trades-pager">
|
||||
<button type="button" class="btn-secondary" id="or-trades-prev" style="font-size:.72rem;padding:2px 8px">上一页</button>
|
||||
<span class="muted" id="or-trades-page-label">1</span>
|
||||
<span class="muted" id="or-trades-page-label">第 1 / 1 页</span>
|
||||
<button type="button" class="btn-secondary" id="or-trades-next" style="font-size:.72rem;padding:2px 8px">下一页</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -179,6 +179,7 @@
|
||||
{# 3. 已复盘记录 + 详情 #}
|
||||
<div class="card" style="margin-bottom:10px">
|
||||
<h3>复盘记录</h3>
|
||||
<p class="muted" style="margin:0 0 8px;font-size:.72rem">已保存的复盘(每页5条).点一行查看详情.</p>
|
||||
<p class="muted" style="margin-top:0;font-size:.72rem">保存后出现在此.点一行查看详情(含截图与完整复盘内容).</p>
|
||||
<div class="options-strike-table-wrap">
|
||||
<table class="options-strike-table or-reviewed-table" id="or-reviewed-table">
|
||||
@@ -197,6 +198,11 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="or-pager" id="or-reviewed-pager">
|
||||
<button type="button" class="btn-secondary" id="or-reviewed-prev" style="font-size:.72rem;padding:2px 8px">上一页</button>
|
||||
<span class="muted" id="or-reviewed-page-label">第 1 / 1 页</span>
|
||||
<button type="button" class="btn-secondary" id="or-reviewed-next" style="font-size:.72rem;padding:2px 8px">下一页</button>
|
||||
</div>
|
||||
<div class="or-detail-panel hidden" id="or-detail-panel">
|
||||
<div class="form-row" style="align-items:center;gap:8px;margin-bottom:6px">
|
||||
<h3 style="margin:0;margin-right:auto" id="or-detail-title">复盘详情</h3>
|
||||
@@ -217,4 +223,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/options_review.js?v=8"></script>
|
||||
<script src="/static/options_review.js?v=9"></script>
|
||||
|
||||
Reference in New Issue
Block a user