Compare commits

...

2 Commits

Author SHA1 Message Date
dekun 38ff40111a 关键位与今日计划列表实时现价及距区间距离(1s轮询)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 14:30:01 +08:00
dekun 58020b6e9c 修复关键位sina_code字段;复盘详情全屏两行;开单计划表单布局优化
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-15 14:22:42 +08:00
8 changed files with 994 additions and 728 deletions
+70 -1
View File
@@ -174,6 +174,7 @@ def init_db():
"ALTER TABLE order_plans ADD COLUMN sina_code TEXT", "ALTER TABLE order_plans ADD COLUMN sina_code TEXT",
"ALTER TABLE order_plans ADD COLUMN market_code TEXT", "ALTER TABLE order_plans ADD COLUMN market_code TEXT",
"ALTER TABLE key_monitors ADD COLUMN market_code TEXT", "ALTER TABLE key_monitors ADD COLUMN market_code TEXT",
"ALTER TABLE key_monitors ADD COLUMN sina_code TEXT",
"ALTER TABLE trade_records ADD COLUMN market_code TEXT", "ALTER TABLE trade_records ADD COLUMN market_code TEXT",
"ALTER TABLE order_plans ADD COLUMN plan_date TEXT", "ALTER TABLE order_plans ADD COLUMN plan_date TEXT",
"ALTER TABLE order_plans ADD COLUMN decision_reason TEXT", "ALTER TABLE order_plans ADD COLUMN decision_reason TEXT",
@@ -480,7 +481,75 @@ def api_symbol_search():
q = request.args.get("q", "") q = request.args.get("q", "")
return jsonify(search_symbols(q)) return jsonify(search_symbols(q))
# —————————————— 页面路由 ——————————————
@app.route("/api/key_prices")
@login_required
def api_key_prices():
"""关键位监控列表:批量现价与距上/下沿距离。"""
conn = get_db()
rows = conn.execute(
"SELECT id, symbol, market_code, sina_code, upper, lower "
"FROM key_monitors WHERE status='active' OR status IS NULL"
).fetchall()
conn.close()
out = []
for r in rows:
sym = r["symbol"]
market = r["market_code"] or ""
sina = r["sina_code"] or ""
upper = float(r["upper"])
lower = float(r["lower"])
price = fetch_price(sym, market, sina)
dist_upper = None
dist_lower = None
if price is not None:
dist_upper = round(upper - price, 2)
dist_lower = round(price - lower, 2)
out.append({
"id": r["id"],
"price": price,
"dist_upper": dist_upper,
"dist_lower": dist_lower,
})
return jsonify(out)
@app.route("/api/plan_prices")
@login_required
def api_plan_prices():
"""今日计划:批量现价与距决策区间上/下沿距离。"""
today = today_str()
conn = get_db()
rows = conn.execute(
"SELECT id, symbol, market_code, sina_code, zone_upper, zone_lower "
"FROM order_plans WHERE plan_date=? AND status IN ('planned', 'active')",
(today,),
).fetchall()
conn.close()
out = []
for r in rows:
sym = r["symbol"]
market = r["market_code"] or ""
sina = r["sina_code"] or ""
upper = float(r["zone_upper"])
lower = float(r["zone_lower"])
price = fetch_price(sym, market, sina)
dist_upper = None
dist_lower = None
in_zone = False
if price is not None:
dist_upper = round(upper - price, 2)
dist_lower = round(price - lower, 2)
in_zone = lower <= price <= upper
out.append({
"id": r["id"],
"price": price,
"dist_upper": dist_upper,
"dist_lower": dist_lower,
"in_zone": in_zone,
})
return jsonify(out)
@app.route("/") @app.route("/")
@login_required @login_required
+39
View File
@@ -0,0 +1,39 @@
(function () {
var timer = null;
function fmtDist(v) {
if (v === null || v === undefined) return '--';
return v.toFixed(2);
}
function pollPrices() {
var list = document.getElementById('key-monitor-list');
if (!list || !list.querySelector('.key-item')) return;
fetch('/api/key_prices')
.then(function (r) { return r.json(); })
.then(function (rows) {
rows.forEach(function (row) {
var el = list.querySelector('.key-item[data-key-id="' + row.id + '"]');
if (!el) return;
var priceEl = el.querySelector('.live-price');
var upEl = el.querySelector('.dist-up');
var downEl = el.querySelector('.dist-down');
if (priceEl) {
priceEl.textContent = row.price != null ? row.price : '--';
}
if (upEl) upEl.textContent = fmtDist(row.dist_upper);
if (downEl) downEl.textContent = fmtDist(row.dist_lower);
});
})
.catch(function () { /* ignore */ });
}
function startPolling() {
if (timer) clearInterval(timer);
pollPrices();
timer = setInterval(pollPrices, 1000);
}
document.addEventListener('DOMContentLoaded', startPolling);
})();
+45
View File
@@ -0,0 +1,45 @@
(function () {
var timer = null;
function fmtDist(v) {
if (v === null || v === undefined) return '--';
return v.toFixed(2);
}
function pollPrices() {
var list = document.getElementById('plan-monitor-list');
if (!list || !list.querySelector('.plan-item')) return;
fetch('/api/plan_prices')
.then(function (r) { return r.json(); })
.then(function (rows) {
rows.forEach(function (row) {
var el = list.querySelector('.plan-item[data-plan-id="' + row.id + '"]');
if (!el) return;
var priceEl = el.querySelector('.live-price');
var distEl = el.querySelector('.live-dist');
var upEl = el.querySelector('.dist-up');
var downEl = el.querySelector('.dist-down');
if (priceEl) {
priceEl.textContent = row.price != null ? row.price : '--';
}
if (row.in_zone && distEl) {
distEl.innerHTML = '<span class="text-profit" style="font-weight:600">在区间内</span>';
} else if (distEl && upEl && downEl) {
distEl.innerHTML =
'距上 <span class="dist-up">' + fmtDist(row.dist_upper) + '</span>' +
' · 距下 <span class="dist-down">' + fmtDist(row.dist_lower) + '</span>';
}
});
})
.catch(function () { /* ignore */ });
}
function startPolling() {
if (timer) clearInterval(timer);
pollPrices();
timer = setInterval(pollPrices, 1000);
}
document.addEventListener('DOMContentLoaded', startPolling);
})();
+68 -16
View File
@@ -59,30 +59,82 @@
}); });
} }
function esc(v) {
if (v === null || v === undefined || v === '') return '-';
return String(v);
}
function fmtTime(v) {
if (!v) return '-';
return String(v).replace('T', ' ').slice(0, 16);
}
function fmtRR(data) {
var init = data.initial_pnl;
var act = data.actual_pnl;
if (init && act) return init + ' / ' + act;
return act || init || '-';
}
function fmtTags(data) {
var tags = data.behavior_tags || '';
if (data.is_emotion && tags.indexOf('情绪') === -1) {
return tags ? '情绪单 · ' + tags : '情绪单';
}
return tags || '-';
}
function showModal(data) { function showModal(data) {
var mask = document.getElementById('review-modal'); var mask = document.getElementById('review-modal');
var body = document.getElementById('review-modal-body'); var body = document.getElementById('review-modal-body');
if (!mask || !body) return; if (!mask || !body) return;
var html = '<div class="modal-grid">';
var fields = [ var labels = [
['品种', data.symbol], ['方向', data.direction], '品种', '合约', '方向', '张数', '周期',
['成交价', data.entry_price], ['止', data.stop_loss], '成交价', '止损', '止', '平仓价',
['止盈', data.take_profit], ['平仓价', data.close_price], '开仓时间', '平仓时间', '持仓时长', '盈利金额', '盈亏比',
['张数', data.lots], ['开仓时间', data.open_time], '开仓类型', '行为标签'
['平仓时间', data.close_time], ['持仓时长', data.holding_duration],
['初始盈亏比', data.initial_pnl], ['实际盈亏比', data.actual_pnl],
['盈亏金额', data.pnl], ['开仓类型', data.open_type],
['离场触发', data.exit_trigger], ['离场补充', data.exit_supplement],
['情绪单', data.is_emotion ? '是' : '否'],
['行为标签', data.behavior_tags], ['备注', data.notes]
]; ];
fields.forEach(function (pair) { var values = [
html += '<div class="item"><label>' + pair[0] + '</label><div>' + (pair[1] || '-') + '</div></div>'; esc(data.symbol),
esc(data.symbol_code),
esc(data.direction),
esc(data.lots),
esc(data.timeframe),
esc(data.entry_price),
esc(data.stop_loss),
esc(data.take_profit),
esc(data.close_price),
fmtTime(data.open_time),
fmtTime(data.close_time),
esc(data.holding_duration),
esc(data.pnl),
fmtRR(data),
esc(data.open_type),
fmtTags(data)
];
var html = '<div class="review-detail-table">';
html += '<div class="review-detail-headers">';
labels.forEach(function (lb) {
html += '<span>' + lb + '</span>';
}); });
html += '</div>'; html += '</div><div class="review-detail-values">';
values.forEach(function (val, i) {
var cls = '';
if (i === 15 && data.is_emotion) cls = ' class="emotion-val"';
html += '<span' + cls + '>' + val + '</span>';
});
html += '</div></div>';
html += '<div class="review-detail-image">';
if (data.screenshot) { if (data.screenshot) {
html += '<div style="margin-top:1rem"><img src="/uploads/' + data.screenshot + '" style="max-width:100%;border-radius:8px"></div>'; html += '<img src="/uploads/' + data.screenshot + '" alt="复盘截图">';
} else {
html += '<div class="no-img">暂无截图 / K线图</div>';
} }
html += '</div>';
body.innerHTML = html; body.innerHTML = html;
mask.classList.add('show'); mask.classList.add('show');
} }
+47 -2
View File
@@ -103,7 +103,7 @@
} }
.page-wrap{max-width:1800px;margin:0 auto;min-height:100vh} .page-wrap{max-width:1800px;margin:0 auto;min-height:100vh}
.site-header{text-align:center;padding:1.5rem 1rem 1.25rem;border-bottom:1px solid var(--border-header);position:relative} .site-header{text-align:center;padding:1.5rem 1rem 1.25rem;border-bottom:1px solid var(--border-header);position:relative}
.site-title{font-size:1.75rem;font-weight:700;color:var(--text-title);margin-bottom:1rem;line-height:1.3} .site-title{font-size:1.75rem;font-weight:700;color:var(--text-title);margin-bottom:1.65rem;line-height:1.3}
.header-tools{position:absolute;top:1rem;left:1.5rem;display:flex;gap:.5rem;align-items:center} .header-tools{position:absolute;top:1rem;left:1.5rem;display:flex;gap:.5rem;align-items:center}
.theme-toggle{ .theme-toggle{
display:flex;align-items:center;gap:.35rem; display:flex;align-items:center;gap:.35rem;
@@ -290,7 +290,52 @@
.modal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:.75rem;font-size:.9rem} .modal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:.75rem;font-size:.9rem}
.modal-grid .item label{color:var(--text-muted);font-size:.75rem;display:block} .modal-grid .item label{color:var(--text-muted);font-size:.75rem;display:block}
.modal-grid .item div{margin-top:.2rem;color:var(--text-primary)} .modal-grid .item div{margin-top:.2rem;color:var(--text-primary)}
.modal-close{float:right;color:var(--text-muted);cursor:pointer;font-size:1.2rem} .form-compact .line-plan-1{grid-template-columns:minmax(0,1fr) minmax(72px,0.45fr) minmax(0,1.6fr)}
.form-compact .line-plan-2{grid-template-columns:repeat(4,minmax(0,1fr)) auto;align-items:center}
.form-compact .field-short select{padding:.55rem .5rem}
.badge.emotion{background:var(--loss-bg);color:var(--loss);font-weight:600;border:1px solid var(--loss)}
tr.row-emotion td{color:var(--loss)}
tr.row-emotion td .badge.emotion{background:var(--loss);color:#fff;border-color:var(--loss)}
.modal-box.review-modal-wide{max-width:960px}
.modal-box.review-modal-fullscreen{
width:calc(100vw - 1.5rem);max-width:none;
height:calc(100vh - 1.5rem);max-height:none;
border-radius:12px;display:flex;flex-direction:column;
}
.modal-box.review-modal-fullscreen h3{flex-shrink:0}
#review-modal-body.review-modal-body{flex:1;overflow:auto;min-height:0}
.review-detail-table{margin-bottom:1rem;overflow-x:auto}
.review-detail-headers,.review-detail-values{
display:grid;
grid-template-columns:repeat(16,minmax(52px,1fr));
gap:.35rem .4rem;align-items:start;
}
.review-detail-headers span{
font-size:.68rem;color:var(--text-muted);
white-space:nowrap;line-height:1.3;
}
.review-detail-values span{
font-size:.82rem;color:var(--text-primary);
line-height:1.35;word-break:break-all;
}
.review-detail-values span.emotion-val{color:var(--loss);font-weight:600}
.review-detail-fields{padding:.25rem 0}
.review-detail-section{margin-bottom:.85rem}
.review-detail-section h4{font-size:.78rem;color:var(--text-label);margin-bottom:.45rem;font-weight:600}
.review-detail-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:.45rem .65rem}
.review-detail-item label{display:block;font-size:.7rem;color:var(--text-muted);margin-bottom:.15rem}
.review-detail-item div{font-size:.85rem;color:var(--text-primary);line-height:1.35}
.review-detail-item.wide{grid-column:span 2}
.review-detail-item.full{grid-column:1/-1}
.review-detail-item.emotion div{color:var(--loss);font-weight:600}
.review-detail-image{flex-shrink:0;padding-top:.75rem;border-top:1px solid var(--table-border)}
.review-detail-image img{width:100%;border-radius:10px;border:1px solid var(--card-border)}
.review-detail-image .no-img{color:var(--text-muted);font-size:.85rem;padding:2rem;text-align:center;background:var(--card-inner);border-radius:10px}
.key-live{display:flex;flex-direction:column;align-items:center;gap:.15rem;min-width:100px;font-size:.8rem}
.key-live .live-price{font-size:1rem;font-weight:600;color:var(--accent)}
.key-live .live-dist{color:var(--text-muted);font-size:.72rem;white-space:nowrap}
.key-live .live-dist span{color:var(--text-primary)}
.list-item.key-item{gap:.65rem}
.calc-readonly{background:var(--calc-bg);color:var(--accent)} .calc-readonly{background:var(--calc-bg);color:var(--accent)}
@media(max-width:1100px){ @media(max-width:1100px){
.split-grid{grid-template-columns:1fr} .split-grid{grid-template-columns:1fr}
+10 -3
View File
@@ -8,7 +8,7 @@
<form action="{{ url_for('add_key') }}" method="post" class="form-compact"> <form action="{{ url_for('add_key') }}" method="post" class="form-compact">
<div class="form-line line-3"> <div class="form-line line-3">
<div class="symbol-wrap"> <div class="symbol-wrap">
<input type="text" class="symbol-input" placeholder="中文名或同花顺代码" autocomplete="off" required> <input type="text" class="symbol-input" placeholder="主力合约" autocomplete="off" required>
<input type="hidden" name="symbol" required> <input type="hidden" name="symbol" required>
<input type="hidden" name="symbol_name"> <input type="hidden" name="symbol_name">
<input type="hidden" name="market_code" required> <input type="hidden" name="market_code" required>
@@ -35,13 +35,17 @@
</div> </div>
</form> </form>
<h3 class="section-label">监控列表</h3> <h3 class="section-label">监控列表</h3>
<div class="list card-scroll"> <div class="list card-scroll" id="key-monitor-list">
{% for k in keys %} {% for k in keys %}
<div class="list-item" style="padding:.75rem;font-size:.85rem"> <div class="list-item key-item" data-key-id="{{ k.id }}" style="padding:.75rem;font-size:.85rem">
<div> <div>
<strong>{{ k.symbol_name or k.symbol }}</strong> {{ k.monitor_type }} <strong>{{ k.symbol_name or k.symbol }}</strong> {{ k.monitor_type }}
<span class="badge dir">{{ '多' if k.direction == 'long' else '空' }}</span> <span class="badge dir">{{ '多' if k.direction == 'long' else '空' }}</span>
</div> </div>
<div class="key-live">
<span class="live-price">--</span>
<span class="live-dist">距上 <span class="dist-up">--</span> · 距下 <span class="dist-down">--</span></span>
</div>
<div>上{{ k.upper }} 下{{ k.lower }}</div> <div>上{{ k.upper }} 下{{ k.lower }}</div>
<a href="{{ url_for('del_key', pid=k.id) }}" class="btn-del" onclick="return confirm('移入历史?')"></a> <a href="{{ url_for('del_key', pid=k.id) }}" class="btn-del" onclick="return confirm('移入历史?')"></a>
</div> </div>
@@ -76,3 +80,6 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/keys.js') }}"></script>
{% endblock %}
+14 -9
View File
@@ -6,11 +6,11 @@
<span class="card-corner tl"></span><span class="card-corner br"></span> <span class="card-corner tl"></span><span class="card-corner br"></span>
<h2>今日计划 <span class="text-muted" style="font-size:.8rem;font-weight:normal">今日 {{ today }}</span></h2> <h2>今日计划 <span class="text-muted" style="font-size:.8rem;font-weight:normal">今日 {{ today }}</span></h2>
<div class="card-body"> <div class="card-body">
<p class="hint" style="margin-bottom:.75rem">开盘前制定,当日有效;下方为进行中计划。</p> <p class="hint" style="margin-bottom:.75rem">开盘前制定,当日有效;请先选择<strong>主力合约</strong>下方为进行中计划。</p>
<form action="{{ url_for('add_plan') }}" method="post" class="form-compact"> <form action="{{ url_for('add_plan') }}" method="post" class="form-compact">
<div class="form-line line-3"> <div class="form-line line-plan-1">
<div class="symbol-wrap"> <div class="symbol-wrap">
<input type="text" class="symbol-input" placeholder="品种" autocomplete="off" required> <input type="text" class="symbol-input" placeholder="主力合约" autocomplete="off" required>
<input type="hidden" name="symbol" required> <input type="hidden" name="symbol" required>
<input type="hidden" name="symbol_name"> <input type="hidden" name="symbol_name">
<input type="hidden" name="market_code" required> <input type="hidden" name="market_code" required>
@@ -18,33 +18,35 @@
<div class="symbol-dropdown"></div> <div class="symbol-dropdown"></div>
<div class="symbol-selected"></div> <div class="symbol-selected"></div>
</div> </div>
<select name="direction" required> <select name="direction" class="field-short" required>
<option value="">方向</option> <option value="">方向</option>
<option value="long">做多</option> <option value="long">做多</option>
<option value="short">做空</option> <option value="short">做空</option>
</select> </select>
<input name="decision_reason" type="text" placeholder="决策理由"> <input name="decision_reason" type="text" placeholder="决策理由">
</div> </div>
<div class="form-line line-4"> <div class="form-line line-plan-2">
<input name="zone_lower" type="number" step="0.0001" placeholder="决策区间下限" required> <input name="zone_lower" type="number" step="0.0001" placeholder="决策区间下限" required>
<input name="zone_upper" type="number" step="0.0001" placeholder="决策区间上限" required> <input name="zone_upper" type="number" step="0.0001" placeholder="决策区间上限" required>
<input name="stop_loss" type="number" step="0.0001" placeholder="止损" required> <input name="stop_loss" type="number" step="0.0001" placeholder="止损" required>
<input name="take_profit" type="number" step="0.0001" placeholder="止盈" required> <input name="take_profit" type="number" step="0.0001" placeholder="止盈" required>
</div>
<div class="form-line line-btn">
<button type="submit" class="btn-primary">添加</button> <button type="submit" class="btn-primary">添加</button>
</div> </div>
</form> </form>
<h3 class="section-label">进行中</h3> <h3 class="section-label">进行中</h3>
<div class="list card-scroll"> <div class="list card-scroll" id="plan-monitor-list">
{% for p in plans %} {% for p in plans %}
<div class="list-item" style="padding:.75rem;font-size:.85rem"> <div class="list-item key-item plan-item" data-plan-id="{{ p.id }}" style="padding:.75rem;font-size:.85rem">
<div> <div>
<strong>{{ p.symbol_name or p.symbol }}</strong> <strong>{{ p.symbol_name or p.symbol }}</strong>
<span class="badge dir">{{ '多' if p.direction == 'long' else '空' }}</span> <span class="badge dir">{{ '多' if p.direction == 'long' else '空' }}</span>
{% if p.status == 'planned' %}<span class="badge planned">待触发</span> {% if p.status == 'planned' %}<span class="badge planned">待触发</span>
{% else %}<span class="badge active">已激活</span>{% endif %} {% else %}<span class="badge active">已激活</span>{% endif %}
</div> </div>
<div class="key-live">
<span class="live-price">--</span>
<span class="live-dist">距上 <span class="dist-up">--</span> · 距下 <span class="dist-down">--</span></span>
</div>
<div> <div>
区间{{ p.zone_lower }}~{{ p.zone_upper }} 区间{{ p.zone_lower }}~{{ p.zone_upper }}
{% if p.decision_reason %} · {{ p.decision_reason }}{% endif %} {% if p.decision_reason %} · {{ p.decision_reason }}{% endif %}
@@ -95,3 +97,6 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block extra_js %}
<script src="{{ url_for('static', filename='js/plans.js') }}"></script>
{% endblock %}
+12 -8
View File
@@ -107,7 +107,7 @@
</thead> </thead>
<tbody> <tbody>
{% for r in reviews %} {% for r in reviews %}
<tr> <tr class="{% if r.is_emotion %}row-emotion{% endif %}">
<td>{{ r.close_time[:16] if r.close_time else '' }}</td> <td>{{ r.close_time[:16] if r.close_time else '' }}</td>
<td>{{ r.symbol_name or r.symbol }}</td> <td>{{ r.symbol_name or r.symbol }}</td>
<td><span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span></td> <td><span class="badge dir">{{ '多' if r.direction == 'long' else '空' }}</span></td>
@@ -116,17 +116,21 @@
{% elif r.pnl and r.pnl < 0 %}<span class="badge loss">{{ r.pnl }}</span> {% elif r.pnl and r.pnl < 0 %}<span class="badge loss">{{ r.pnl }}</span>
{% else %}{{ r.actual_pnl or '-' }}{% endif %} {% else %}{{ r.actual_pnl or '-' }}{% endif %}
</td> </td>
<td>{% if r.is_emotion %}<span class="badge loss">情绪</span>{% else %}-{% endif %}</td> <td>{% if r.is_emotion %}<span class="badge emotion">情绪</span>{% else %}-{% endif %}</td>
<td> <td>
<button type="button" class="btn-link review-view-btn" data-review='{{ { <button type="button" class="btn-link review-view-btn" data-review='{{ {
"symbol": r.symbol_name or r.symbol, "symbol_code": r.symbol, "direction": "做多" if r.direction=="long" else "做空", "symbol": r.symbol_name or r.symbol, "symbol_code": r.symbol,
"direction": "做多" if r.direction=="long" else "做空",
"lots": r.lots, "timeframe": r.timeframe,
"entry_price": r.entry_price, "stop_loss": r.stop_loss, "take_profit": r.take_profit, "entry_price": r.entry_price, "stop_loss": r.stop_loss, "take_profit": r.take_profit,
"close_price": r.close_price, "lots": r.lots, "close_price": r.close_price,
"open_time": r.open_time, "close_time": r.close_time, "open_time": r.open_time, "close_time": r.close_time,
"holding_duration": r.holding_duration, "initial_pnl": r.initial_pnl, "holding_duration": r.holding_duration,
"actual_pnl": r.actual_pnl, "pnl": r.pnl, "initial_pnl": r.initial_pnl, "actual_pnl": r.actual_pnl, "pnl": r.pnl,
"open_type": r.open_type, "open_type": r.open_type,
"exit_trigger": r.exit_trigger, "exit_supplement": r.exit_supplement, "exit_trigger": r.exit_trigger, "exit_supplement": r.exit_supplement,
"watch_after_breakeven": r.watch_after_breakeven,
"new_position_while_occupied": r.new_position_while_occupied,
"is_emotion": r.is_emotion, "behavior_tags": r.behavior_tags, "is_emotion": r.is_emotion, "behavior_tags": r.behavior_tags,
"notes": r.notes, "screenshot": r.screenshot "notes": r.notes, "screenshot": r.screenshot
} | tojson }}'>放大查看</button> } | tojson }}'>放大查看</button>
@@ -144,10 +148,10 @@
</div> </div>
<div id="review-modal" class="modal-mask"> <div id="review-modal" class="modal-mask">
<div class="modal-box"> <div class="modal-box review-modal-fullscreen">
<span class="modal-close"></span> <span class="modal-close"></span>
<h3>复盘详情</h3> <h3>复盘详情</h3>
<div id="review-modal-body"></div> <div id="review-modal-body" class="review-modal-body"></div>
</div> </div>
</div> </div>