Clarify options review layout with numbered sections and KPI tiles.
Separate trade/review/stats blocks, tuck filters into a toolbar, and hide empty stat groups so the page scans more easily. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -695,24 +695,18 @@
|
||||
}
|
||||
|
||||
function renderGroup(title, items) {
|
||||
if (!items || !items.length) {
|
||||
return (
|
||||
'<div class="or-stat-card"><div class="muted">' +
|
||||
title +
|
||||
'</div><div class="muted">无数据</div></div>'
|
||||
);
|
||||
}
|
||||
if (!items || !items.length) return "";
|
||||
var lines = items
|
||||
.slice(0, 8)
|
||||
.map(function (g) {
|
||||
return (
|
||||
'<div style="display:flex;justify-content:space-between;gap:8px;font-size:13px">' +
|
||||
"<span>" +
|
||||
'<div class="or-stat-row">' +
|
||||
'<span class="or-stat-key">' +
|
||||
escapeHtml(g.key) +
|
||||
" · " +
|
||||
g.count +
|
||||
"笔</span>" +
|
||||
"<span>" +
|
||||
'<span class="or-stat-val">' +
|
||||
fmtPnl(g.pnl_sum) +
|
||||
" / 胜" +
|
||||
(g.win_rate || 0) +
|
||||
@@ -722,7 +716,7 @@
|
||||
})
|
||||
.join("");
|
||||
return (
|
||||
'<div class="or-stat-card"><div style="font-weight:600;margin-bottom:6px">' +
|
||||
'<div class="or-stat-card"><div class="or-stat-card-title">' +
|
||||
title +
|
||||
"</div>" +
|
||||
lines +
|
||||
@@ -750,23 +744,31 @@
|
||||
["平均持有", fmtHold(k.avg_hold_sec)],
|
||||
]
|
||||
.map(function (pair) {
|
||||
var style = "";
|
||||
if (pair[0] === "累计盈亏") style = pnlStyle(k.pnl_sum);
|
||||
if (pair[0] === "平均盈亏") style = pnlStyle(k.avg_pnl);
|
||||
return (
|
||||
'<div><div class="muted" style="font-size:12px">' +
|
||||
'<div class="or-kpi-tile"><div class="or-kpi-label">' +
|
||||
pair[0] +
|
||||
'</div><div style="font-weight:600">' +
|
||||
'</div><div class="or-kpi-value" style="' +
|
||||
style +
|
||||
'">' +
|
||||
pair[1] +
|
||||
"</div></div>"
|
||||
);
|
||||
})
|
||||
.join("");
|
||||
groups.innerHTML = [
|
||||
var html = [
|
||||
renderGroup("按类型", data.by_source_type),
|
||||
renderGroup("按标的", data.by_underlying),
|
||||
renderGroup("按策略", data.by_strategy),
|
||||
renderGroup("对冲结束原因", data.by_close_reason),
|
||||
renderGroup("持有周期", data.by_hold_bucket),
|
||||
renderGroup("Call/Put", data.by_opt_type),
|
||||
].join("");
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("");
|
||||
groups.innerHTML = html || '<div class="muted" style="font-size:.76rem">暂无分组数据</div>';
|
||||
})
|
||||
.catch(function () {});
|
||||
}
|
||||
|
||||
@@ -1,20 +1,103 @@
|
||||
{# OKX 期权复盘:交易记录(5行) → 点复盘出表单 → 复盘记录 → 统计 #}
|
||||
{# OKX 期权复盘:交易记录 → 复盘表单 → 复盘记录 → 统计 #}
|
||||
<div class="options-review-wrap" id="options-review-root" style="grid-column:1/-1">
|
||||
{% if not options_enabled %}
|
||||
<div class="flash" style="margin-bottom:12px;font-size:.82rem">期权未启用:请设置 <code>OKX_OPTIONS_ENABLED=true</code> 后重启.</div>
|
||||
{% endif %}
|
||||
|
||||
<style>
|
||||
.options-review-wrap{font-size:.82rem}
|
||||
.options-review-wrap h2{font-size:1rem;margin:0 0 8px}
|
||||
.options-review-wrap h3{font-size:.9rem;margin:0 0 8px}
|
||||
.or-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px}
|
||||
.or-tab{border:1px solid rgba(127,127,127,.35);background:transparent;color:inherit;padding:5px 10px;border-radius:6px;cursor:pointer;font-size:.78rem}
|
||||
.or-tab.active{background:rgba(59,130,246,.25);border-color:rgba(59,130,246,.55)}
|
||||
.or-badge{display:inline-block;padding:1px 6px;border-radius:999px;background:rgba(127,127,127,.2);font-size:.7rem}
|
||||
.or-stat-card{border:1px solid rgba(127,127,127,.25);border-radius:8px;padding:8px;font-size:.78rem}
|
||||
.or-trades-table{font-size:.78rem}
|
||||
.or-trades-table tr.or-row-active{outline:1px solid rgba(59,130,246,.55);background:rgba(59,130,246,.08)}
|
||||
.options-review-wrap{font-size:.82rem;display:flex;flex-direction:column;gap:14px}
|
||||
.options-review-wrap h2,.options-review-wrap h3{margin:0}
|
||||
.or-page-head{
|
||||
display:flex;align-items:center;gap:10px;flex-wrap:wrap;
|
||||
padding:2px 2px 0;
|
||||
}
|
||||
.or-page-head h2{font-size:1.05rem;font-weight:650;margin-right:auto;letter-spacing:.02em}
|
||||
.or-section{
|
||||
margin:0;padding:14px 16px 16px;
|
||||
border:1px solid rgba(127,127,127,.28);
|
||||
border-radius:12px;
|
||||
background:rgba(18,23,38,.55);
|
||||
box-shadow:0 1px 0 rgba(255,255,255,.03) inset;
|
||||
}
|
||||
.or-section-head{
|
||||
display:flex;align-items:flex-start;gap:10px;flex-wrap:wrap;
|
||||
margin-bottom:12px;padding-bottom:10px;
|
||||
border-bottom:1px solid rgba(127,127,127,.22);
|
||||
}
|
||||
.or-section-head > div{min-width:0;flex:1}
|
||||
.or-step{
|
||||
flex-shrink:0;width:1.55rem;height:1.55rem;border-radius:999px;
|
||||
display:inline-flex;align-items:center;justify-content:center;
|
||||
font-size:.72rem;font-weight:700;
|
||||
background:rgba(99,102,241,.28);color:#c7c9ff;
|
||||
border:1px solid rgba(129,140,248,.45);
|
||||
}
|
||||
.or-section-title{font-size:.95rem;font-weight:650;line-height:1.3}
|
||||
.or-section-desc{margin:4px 0 0;font-size:.72rem;opacity:.72;line-height:1.45}
|
||||
.or-tabs{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px}
|
||||
.or-tab{
|
||||
border:1px solid rgba(127,127,127,.35);background:transparent;color:inherit;
|
||||
padding:6px 12px;border-radius:8px;cursor:pointer;font-size:.78rem;
|
||||
}
|
||||
.or-tab.active{
|
||||
background:rgba(99,102,241,.28);border-color:rgba(129,140,248,.55);
|
||||
color:#e8e9ff;font-weight:600;
|
||||
}
|
||||
.or-filters{
|
||||
display:flex;flex-wrap:wrap;gap:8px;align-items:center;
|
||||
margin-bottom:12px;padding:10px 12px;border-radius:10px;
|
||||
background:rgba(0,0,0,.22);border:1px solid rgba(127,127,127,.18);
|
||||
}
|
||||
.or-filters select,.or-filters input[type="search"],.or-filters input[type="datetime-local"]{
|
||||
font-size:.76rem;min-height:2rem;
|
||||
}
|
||||
.or-filters #or-filter-q{max-width:168px}
|
||||
.or-filters label{display:flex;align-items:center;gap:5px;font-size:.72rem;opacity:.85}
|
||||
.or-badge{
|
||||
display:inline-block;padding:1px 7px;border-radius:999px;
|
||||
background:rgba(127,127,127,.22);font-size:.7rem;vertical-align:middle;
|
||||
}
|
||||
.or-list-title{display:none}
|
||||
.or-trades-table,.or-reviewed-table{font-size:.78rem}
|
||||
.or-trades-table tr.or-row-active{
|
||||
outline:1px solid rgba(129,140,248,.55);background:rgba(99,102,241,.1);
|
||||
}
|
||||
.or-reviewed-table tbody tr{cursor:pointer}
|
||||
.or-reviewed-table tbody tr:hover{background:rgba(99,102,241,.08)}
|
||||
.or-pager{
|
||||
display:flex;align-items:center;gap:8px;margin-top:10px;
|
||||
padding-top:8px;border-top:1px dashed rgba(127,127,127,.2);font-size:.74rem;
|
||||
}
|
||||
.or-list-loading{opacity:.55;pointer-events:none;transition:opacity .12s ease}
|
||||
.or-trades-table-wrap,.or-reviewed-table-wrap{min-height:9.5rem}
|
||||
.or-kpi-row{
|
||||
display:grid;grid-template-columns:repeat(6,minmax(0,1fr));
|
||||
gap:8px;margin-bottom:12px;
|
||||
}
|
||||
.or-kpi-tile{
|
||||
border:1px solid rgba(127,127,127,.22);border-radius:10px;
|
||||
padding:10px 12px;background:rgba(0,0,0,.2);min-width:0;
|
||||
}
|
||||
.or-kpi-label{font-size:.7rem;opacity:.7;margin-bottom:4px}
|
||||
.or-kpi-value{font-size:.95rem;font-weight:650;letter-spacing:.01em;word-break:break-all}
|
||||
.or-stats-grid{
|
||||
display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px;
|
||||
}
|
||||
.or-stat-card{
|
||||
border:1px solid rgba(127,127,127,.22);border-radius:10px;
|
||||
padding:10px 12px;background:rgba(0,0,0,.16);font-size:.76rem;
|
||||
}
|
||||
.or-stat-card-title{
|
||||
font-weight:650;margin-bottom:8px;font-size:.78rem;
|
||||
padding-bottom:6px;border-bottom:1px solid rgba(127,127,127,.18);
|
||||
}
|
||||
.or-stat-row{
|
||||
display:flex;justify-content:space-between;align-items:baseline;gap:10px;
|
||||
padding:5px 0;border-bottom:1px solid rgba(127,127,127,.1);
|
||||
}
|
||||
.or-stat-row:last-child{border-bottom:none;padding-bottom:0}
|
||||
.or-stat-key{opacity:.9;min-width:0;overflow:hidden;text-overflow:ellipsis}
|
||||
.or-stat-val{flex-shrink:0;font-variant-numeric:tabular-nums;opacity:.85}
|
||||
.or-journal-card{font-size:.78rem}
|
||||
.or-journal-card h2{font-size:.92rem}
|
||||
.or-journal-card input,
|
||||
@@ -22,12 +105,12 @@
|
||||
.or-journal-card textarea,
|
||||
.or-journal-card button{font-size:.76rem}
|
||||
.or-journal-card .or-form-grid,
|
||||
.or-journal-card .or-form-grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;margin-bottom:6px}
|
||||
.or-journal-card .or-form-grid2{
|
||||
display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:6px;margin-bottom:6px;
|
||||
}
|
||||
.or-journal-card .or-mood-grid{display:flex;flex-wrap:wrap;gap:6px 12px;margin:8px 0;font-size:.74rem}
|
||||
.or-journal-card .muted,
|
||||
.or-journal-card .sub{font-size:.7rem}
|
||||
.or-journal-card .muted,.or-journal-card .sub{font-size:.7rem}
|
||||
.or-journal-card.hidden{display:none!important}
|
||||
.or-reviewed-table tbody tr{cursor:pointer}
|
||||
.or-detail-backdrop{
|
||||
position:fixed;inset:0;z-index:1300;
|
||||
display:flex;align-items:center;justify-content:center;
|
||||
@@ -72,58 +155,63 @@
|
||||
min-height:120px;display:flex;align-items:center;justify-content:center;
|
||||
font-size:.72rem;opacity:.65;border-radius:6px;background:rgba(127,127,127,.12);
|
||||
}
|
||||
@media (max-width:640px){
|
||||
.or-detail-images{grid-template-columns:1fr}
|
||||
.or-detail-img-thumb{max-height:220px}
|
||||
}
|
||||
.or-pager{display:flex;align-items:center;gap:8px;margin-top:8px;font-size:.74rem}
|
||||
.or-list-loading{opacity:.55;pointer-events:none;transition:opacity .12s ease}
|
||||
.or-trades-table-wrap,.or-reviewed-table-wrap{min-height:9.5rem}
|
||||
.or-slot-thumb{
|
||||
display:block;margin-top:6px;max-width:160px;max-height:90px;
|
||||
object-fit:contain;border-radius:4px;border:1px solid rgba(127,127,127,.3);
|
||||
background:rgba(0,0,0,.2);cursor:zoom-in;
|
||||
}
|
||||
@media (max-width:900px){
|
||||
.or-kpi-row{grid-template-columns:repeat(3,minmax(0,1fr))}
|
||||
}
|
||||
@media (max-width:640px){
|
||||
.or-kpi-row{grid-template-columns:repeat(2,minmax(0,1fr))}
|
||||
.or-detail-images{grid-template-columns:1fr}
|
||||
.or-detail-img-thumb{max-height:220px}
|
||||
}
|
||||
</style>
|
||||
|
||||
{# 1. 交易记录(含 Tab/筛选,固定约5行) #}
|
||||
<div class="card" style="margin-bottom:10px">
|
||||
<div class="form-row" style="flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:6px">
|
||||
<h2 style="margin:0;margin-right:auto">期权复盘</h2>
|
||||
<span class="muted" id="or-sync-status" style="font-size:.72rem"></span>
|
||||
<button type="button" class="btn-secondary" id="or-reload-btn" style="font-size:.76rem;padding:4px 10px">刷新</button>
|
||||
<div class="or-page-head">
|
||||
<h2>期权复盘</h2>
|
||||
<span class="muted" id="or-sync-status" style="font-size:.72rem"></span>
|
||||
<button type="button" class="btn-secondary" id="or-reload-btn" style="font-size:.76rem;padding:4px 10px">刷新</button>
|
||||
</div>
|
||||
|
||||
{# 1. 交易记录 #}
|
||||
<section class="or-section" aria-labelledby="or-list-title">
|
||||
<div class="or-section-head">
|
||||
<span class="or-step" aria-hidden="true">1</span>
|
||||
<div>
|
||||
<div class="or-section-title" id="or-list-title">期权交易记录</div>
|
||||
<p class="or-section-desc">点「复盘」填写表单;已复盘仍保留在此,也可在下方查看详情。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="or-tabs" role="tablist" aria-label="复盘分类">
|
||||
<button type="button" class="or-tab active" data-source="option_spot" role="tab">期权交易记录</button>
|
||||
<button type="button" class="or-tab" data-source="options_options" role="tab">期期对冲记录</button>
|
||||
<button type="button" class="or-tab" data-source="perp_options" role="tab">永期对冲记录</button>
|
||||
</div>
|
||||
<p class="muted" style="margin:0 0 8px;font-size:.72rem">交易记录(每页5条).点「复盘」填写表单;已复盘仍保留在此列表,也可在下方查看详情.</p>
|
||||
<div class="form-row" style="flex-wrap:wrap;gap:6px;margin-bottom:8px">
|
||||
<select id="or-filter-uly" style="font-size:.76rem" autocomplete="off">
|
||||
<div class="or-filters">
|
||||
<select id="or-filter-uly" autocomplete="off">
|
||||
<option value="">标的:全部</option>
|
||||
<option value="ETH">ETH</option>
|
||||
<option value="BTC">BTC</option>
|
||||
</select>
|
||||
<select id="or-filter-opt" style="font-size:.76rem" autocomplete="off">
|
||||
<select id="or-filter-opt" autocomplete="off">
|
||||
<option value="">Call/Put:全部</option>
|
||||
<option value="C">Call</option>
|
||||
<option value="P">Put</option>
|
||||
</select>
|
||||
{# 诱饵框吸收浏览器把用户名(dekun)填进搜索框 #}
|
||||
<input type="text" name="username" autocomplete="username" tabindex="-1" aria-hidden="true"
|
||||
style="position:absolute;left:-9999px;width:1px;height:1px;opacity:0" value="">
|
||||
<input type="search" id="or-filter-q" name="or_filter_q" placeholder="搜索标的/合约/策略"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-lpignore="true" data-1p-ignore="true" data-form-type="other"
|
||||
readonly style="max-width:150px;font-size:.76rem">
|
||||
<input type="datetime-local" id="or-filter-from" title="平仓起" autocomplete="off" style="font-size:.76rem">
|
||||
<input type="datetime-local" id="or-filter-to" title="平仓止" autocomplete="off" style="font-size:.76rem">
|
||||
<label class="muted" style="display:flex;align-items:center;gap:4px;font-size:.72rem">
|
||||
data-lpignore="true" data-1p-ignore="true" data-form-type="other" readonly>
|
||||
<input type="datetime-local" id="or-filter-from" title="平仓起" autocomplete="off">
|
||||
<input type="datetime-local" id="or-filter-to" title="平仓止" autocomplete="off">
|
||||
<label class="muted">
|
||||
<input type="checkbox" id="or-include-hedge-legs"> 含已归属对冲的期权腿
|
||||
</label>
|
||||
</div>
|
||||
<h3 id="or-list-title" style="margin-top:0">期权交易记录</h3>
|
||||
<div class="options-strike-table-wrap or-trades-table-wrap" id="or-trades-wrap">
|
||||
<table class="options-strike-table or-trades-table" id="or-trades-table">
|
||||
<thead>
|
||||
@@ -147,12 +235,17 @@
|
||||
<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>
|
||||
</section>
|
||||
|
||||
{# 2. 复盘上传(默认隐藏,点交易「复盘」后显示) #}
|
||||
<div class="card journal-card or-journal-card hidden" id="or-journal-card" style="margin-bottom:10px">
|
||||
<h2>复盘记录上传(含截图)</h2>
|
||||
<p class="muted" id="or-journal-summary" style="margin-top:0">截图槽位与合约复盘相同(5m / 15m / 1h / 4h).</p>
|
||||
{# 2. 复盘上传(默认隐藏) #}
|
||||
<section class="or-section journal-card or-journal-card hidden" id="or-journal-card">
|
||||
<div class="or-section-head">
|
||||
<span class="or-step" aria-hidden="true">✎</span>
|
||||
<div>
|
||||
<div class="or-section-title">填写复盘</div>
|
||||
<p class="or-section-desc" id="or-journal-summary">截图槽位 5m / 15m / 1h / 4h,选文件后即时上传。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="or-journal-body">
|
||||
<form id="or-journal-form" onsubmit="return false;">
|
||||
<input type="hidden" id="or-trade-id" value="">
|
||||
@@ -228,12 +321,17 @@
|
||||
<div id="or-legs-host" style="margin-top:10px;font-size:.74rem"></div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# 3. 已复盘记录 + 详情 #}
|
||||
<div class="card" style="margin-bottom:10px">
|
||||
<h3>复盘记录</h3>
|
||||
<p class="muted" style="margin:0 0 8px;font-size:.72rem">已保存的复盘(每页5条).点一行查看详情.</p>
|
||||
{# 3. 已复盘记录 #}
|
||||
<section class="or-section" aria-labelledby="or-reviewed-heading">
|
||||
<div class="or-section-head">
|
||||
<span class="or-step" aria-hidden="true">2</span>
|
||||
<div>
|
||||
<div class="or-section-title" id="or-reviewed-heading">复盘记录</div>
|
||||
<p class="or-section-desc">已保存的复盘内容,点一行查看详情与截图。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="options-strike-table-wrap or-reviewed-table-wrap" id="or-reviewed-wrap">
|
||||
<table class="options-strike-table or-reviewed-table" id="or-reviewed-table">
|
||||
<thead>
|
||||
@@ -258,9 +356,9 @@
|
||||
<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>
|
||||
</section>
|
||||
|
||||
{# 复盘详情对话框(点复盘记录行打开) #}
|
||||
{# 详情 / 放大 #}
|
||||
<div id="or-detail-backdrop" class="or-detail-backdrop" hidden>
|
||||
<div class="or-detail-modal" role="dialog" aria-modal="true" aria-labelledby="or-detail-title" id="or-detail-panel">
|
||||
<div class="or-detail-modal-head">
|
||||
@@ -273,17 +371,22 @@
|
||||
<div class="or-detail-images" id="or-detail-images"></div>
|
||||
</div>
|
||||
</div>
|
||||
{# 截图放大层(高于详情弹窗) #}
|
||||
<div id="or-img-lightbox" class="or-img-lightbox" hidden>
|
||||
<img id="or-img-lightbox-img" src="" alt="截图放大">
|
||||
</div>
|
||||
|
||||
{# 4. 统计 #}
|
||||
<div class="card" style="margin-bottom:10px">
|
||||
<h3>统计</h3>
|
||||
<div id="or-kpi" class="form-row" style="flex-wrap:wrap;gap:10px"></div>
|
||||
<div id="or-stats-groups" style="margin-top:10px;display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:8px"></div>
|
||||
</div>
|
||||
<section class="or-section" aria-labelledby="or-stats-heading">
|
||||
<div class="or-section-head">
|
||||
<span class="or-step" aria-hidden="true">3</span>
|
||||
<div>
|
||||
<div class="or-section-title" id="or-stats-heading">统计</div>
|
||||
<p class="or-section-desc">跟随上方 Tab 与筛选条件汇总。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="or-kpi" class="or-kpi-row"></div>
|
||||
<div id="or-stats-groups" class="or-stats-grid"></div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<script src="/static/options_review.js?v=16"></script>
|
||||
<script src="/static/options_review.js?v=17"></script>
|
||||
|
||||
Reference in New Issue
Block a user