feat: 系统设置 CTP 连接拆分为 SimNow/实盘可折叠卡片
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+84
-10
@@ -16,11 +16,29 @@
|
||||
.settings-tips li::before{content:"";position:absolute;left:0;top:.55em;width:5px;height:5px;border-radius:50%;background:var(--accent)}
|
||||
.settings-ctp-grid{display:grid;grid-template-columns:1fr 1fr;gap:.65rem .75rem}
|
||||
.settings-ctp-grid .field-full{grid-column:1/-1}
|
||||
.settings-ctp-section{margin-bottom:1rem;padding-bottom:1rem;border-bottom:1px solid var(--border)}
|
||||
.settings-ctp-section:last-of-type{border-bottom:none;margin-bottom:0;padding-bottom:0}
|
||||
.settings-ctp-section h3{font-size:.9rem;margin:0 0 .65rem;color:var(--text-title)}
|
||||
.settings-ctp-wrap .card-body{padding-top:0}
|
||||
.settings-ctp-fold.card{
|
||||
margin-bottom:.75rem;padding:0;overflow:hidden;
|
||||
border:1px solid var(--border);border-radius:8px;background:var(--card-inner);
|
||||
}
|
||||
.settings-ctp-fold.card:last-of-type{margin-bottom:0}
|
||||
.settings-ctp-fold-head{
|
||||
width:100%;display:flex;align-items:center;justify-content:space-between;gap:.75rem;
|
||||
padding:.7rem 1rem;margin:0;border:none;background:transparent;cursor:pointer;
|
||||
font-size:.92rem;font-weight:600;color:var(--text-title);text-align:left;
|
||||
}
|
||||
.settings-ctp-fold-head:hover{color:var(--accent)}
|
||||
.settings-ctp-fold-title{display:flex;align-items:center;gap:.5rem}
|
||||
.settings-ctp-fold-chevron{
|
||||
flex-shrink:0;font-size:.72rem;color:var(--text-muted);
|
||||
transition:transform .2s ease;
|
||||
}
|
||||
.settings-ctp-fold.is-collapsed .settings-ctp-fold-chevron{transform:rotate(-90deg)}
|
||||
.settings-ctp-fold-body{padding:0 1rem .85rem}
|
||||
.settings-ctp-fold.is-collapsed .settings-ctp-fold-body{display:none}
|
||||
.settings-ctp-status{font-size:.82rem;color:var(--text-muted);margin-top:.75rem;line-height:1.5}
|
||||
@media(max-width:900px){
|
||||
.settings-password-form{grid-template-columns:1fr}
|
||||
.settings-ctp-grid{grid-template-columns:1fr}
|
||||
}
|
||||
</style>
|
||||
@@ -90,10 +108,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card settings-ctp-wrap">
|
||||
<h2>CTP 连接</h2>
|
||||
<form action="{{ url_for('settings') }}" method="post">
|
||||
<input type="hidden" name="action" value="ctp">
|
||||
<div class="card-body">
|
||||
<p class="hint" style="margin-bottom:.85rem">
|
||||
投资者代码、密码、前置地址在此维护(优先于 <code>.env</code>)。保存后请在持仓监控页点击「重连 CTP」。
|
||||
{% if ctp_status.connected %}
|
||||
@@ -105,8 +122,18 @@
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
<div class="settings-ctp-section">
|
||||
<h3>SimNow 模拟盘</h3>
|
||||
<form action="{{ url_for('settings') }}" method="post" id="ctp-settings-form">
|
||||
<input type="hidden" name="action" value="ctp">
|
||||
|
||||
<div class="settings-ctp-fold card{% if trading_mode != 'simulation' %} is-collapsed{% endif %}" data-ctp-fold="simnow">
|
||||
<button type="button" class="settings-ctp-fold-head" aria-expanded="{{ 'true' if trading_mode == 'simulation' else 'false' }}">
|
||||
<span class="settings-ctp-fold-title">
|
||||
SimNow 模拟盘
|
||||
{% if trading_mode == 'simulation' %}<span class="badge planned" style="font-size:.7rem">当前通道</span>{% endif %}
|
||||
</span>
|
||||
<span class="settings-ctp-fold-chevron" aria-hidden="true">▼</span>
|
||||
</button>
|
||||
<div class="settings-ctp-fold-body">
|
||||
<div class="settings-ctp-grid">
|
||||
<div class="field">
|
||||
<label>投资者代码</label>
|
||||
@@ -146,9 +173,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-ctp-section">
|
||||
<h3>期货公司实盘(后期)</h3>
|
||||
<div class="settings-ctp-fold card{% if trading_mode != 'live' %} is-collapsed{% endif %}" data-ctp-fold="live">
|
||||
<button type="button" class="settings-ctp-fold-head" aria-expanded="{{ 'true' if trading_mode == 'live' else 'false' }}">
|
||||
<span class="settings-ctp-fold-title">
|
||||
期货公司实盘
|
||||
{% if trading_mode == 'live' %}<span class="badge planned" style="font-size:.7rem">当前通道</span>{% endif %}
|
||||
</span>
|
||||
<span class="settings-ctp-fold-chevron" aria-hidden="true">▼</span>
|
||||
</button>
|
||||
<div class="settings-ctp-fold-body">
|
||||
<div class="settings-ctp-grid">
|
||||
<div class="field">
|
||||
<label>投资者代码</label>
|
||||
@@ -188,6 +223,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn-primary">保存 CTP 配置</button>
|
||||
<p class="settings-ctp-status">
|
||||
@@ -197,6 +233,7 @@
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="split-grid">
|
||||
<div class="card">
|
||||
@@ -278,6 +315,43 @@
|
||||
}
|
||||
if (sel) sel.addEventListener('change', syncSizingFields);
|
||||
syncSizingFields();
|
||||
|
||||
var CTP_FOLD_KEY = 'qihuo_ctp_fold';
|
||||
function setCtpFold(el, collapsed) {
|
||||
if (!el) return;
|
||||
el.classList.toggle('is-collapsed', collapsed);
|
||||
var head = el.querySelector('.settings-ctp-fold-head');
|
||||
if (head) head.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
||||
}
|
||||
function saveCtpFoldState() {
|
||||
var state = {};
|
||||
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
||||
state[el.getAttribute('data-ctp-fold')] = el.classList.contains('is-collapsed');
|
||||
});
|
||||
try { localStorage.setItem(CTP_FOLD_KEY, JSON.stringify(state)); } catch (e) { /* ignore */ }
|
||||
}
|
||||
function loadCtpFoldState() {
|
||||
try {
|
||||
var raw = localStorage.getItem(CTP_FOLD_KEY);
|
||||
if (!raw) return;
|
||||
var state = JSON.parse(raw);
|
||||
document.querySelectorAll('[data-ctp-fold]').forEach(function (el) {
|
||||
var key = el.getAttribute('data-ctp-fold');
|
||||
if (Object.prototype.hasOwnProperty.call(state, key)) {
|
||||
setCtpFold(el, !!state[key]);
|
||||
}
|
||||
});
|
||||
} catch (e) { /* ignore */ }
|
||||
}
|
||||
document.querySelectorAll('.settings-ctp-fold-head').forEach(function (btn) {
|
||||
btn.addEventListener('click', function () {
|
||||
var panel = btn.closest('[data-ctp-fold]');
|
||||
if (!panel) return;
|
||||
setCtpFold(panel, !panel.classList.contains('is-collapsed'));
|
||||
saveCtpFoldState();
|
||||
});
|
||||
});
|
||||
loadCtpFoldState();
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user