Collapse field hints into a default-folded 规则说明 on strategy and runtime settings.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-26 21:52:49 +08:00
parent ca66c494e7
commit aca9d80e64
2 changed files with 159 additions and 41 deletions
+105 -41
View File
@@ -1,4 +1,4 @@
import { FormEvent, useEffect, useState } from "react";
import { FormEvent, ReactNode, useEffect, useState } from "react";
import {
changeCredentials,
getUsername,
@@ -15,9 +15,38 @@ type StratSub =
| "exit"
| "pace";
function RulesFold({
open,
onToggle,
children,
}: {
open: boolean;
onToggle: () => void;
children: ReactNode;
}) {
return (
<div className={`settings-rules ${open ? "open" : ""}`}>
<button
type="button"
className="settings-rules-toggle"
aria-expanded={open}
onClick={onToggle}
>
<span></span>
<span className="settings-rules-chevron" aria-hidden>
{open ? "▾" : "▸"}
</span>
</button>
{open ? <div className="settings-rules-body">{children}</div> : null}
</div>
);
}
export default function SettingsPage() {
const [tab, setTab] = useState<Tab>("strategy");
const [stratSub, setStratSub] = useState<StratSub>("position");
const [stratRulesOpen, setStratRulesOpen] = useState(false);
const [runtimeRulesOpen, setRuntimeRulesOpen] = useState(false);
const [newUsername, setNewUsername] = useState(getUsername() || "admin");
const [currentPassword, setCurrentPassword] = useState("");
@@ -247,11 +276,6 @@ export default function SettingsPage() {
{tab === "strategy" ? (
<div className="card settings-card">
<p className="settings-lead">
{(runtime?.mode ?? mode) === "LIVE"
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
</p>
{stratOk ? <div className="settings-ok">{stratOk}</div> : null}
{err && tab === "strategy" ? <div className="err">{err}</div> : null}
@@ -301,9 +325,6 @@ export default function SettingsPage() {
USDT +
</option>
</select>
<p className="settings-hint">
</p>
</div>
{(runtime?.mode ?? mode) !== "LIVE" ? (
<div className="field">
@@ -319,9 +340,6 @@ export default function SettingsPage() {
setInitialEquity(Number(e.target.value))
}
/>
<p className="settings-hint">
SIM 10000
</p>
</div>
) : null}
<div className="field">
@@ -405,9 +423,6 @@ export default function SettingsPage() {
<option value="0"></option>
<option value="1"></option>
</select>
<p className="settings-hint">
|ATM |
</p>
</div>
<div className="field">
<label htmlFor="atmoff"> ATM </label>
@@ -421,9 +436,6 @@ export default function SettingsPage() {
value={maxAtmOff}
onChange={(e) => setMaxAtmOff(Number(e.target.value))}
/>
<p className="settings-hint">
</p>
</div>
</div>
</section>
@@ -491,9 +503,6 @@ export default function SettingsPage() {
value={closeDevPct}
onChange={(e) => setCloseDevPct(Number(e.target.value))}
/>
<p className="settings-hint">
SIM LIVE
</p>
</div>
</div>
</section>
@@ -530,9 +539,6 @@ export default function SettingsPage() {
setOrderInterval(Number(e.target.value))
}
/>
<p className="settings-hint">
LIVE / 1s 0.230
</p>
</div>
<div className="field">
<label htmlFor="skipWe"></label>
@@ -561,6 +567,53 @@ export default function SettingsPage() {
</section>
) : null}
<RulesFold
open={stratRulesOpen}
onToggle={() => setStratRulesOpen((v) => !v)}
>
<ul className="settings-rules-list">
<li>
{(runtime?.mode ?? mode) === "LIVE"
? "当前 LIVE:仓位/选约/出场影响真下单;模拟资金已隐藏。"
: "当前 SIM:本地撮合;可改模拟资金与交易所行情源。"}
</li>
{stratSub === "position" ? (
<>
<li></li>
{(runtime?.mode ?? mode) !== "LIVE" ? (
<li>
SIM
10000
</li>
) : null}
</>
) : null}
{stratSub === "select" ? (
<>
<li>
ATM |ATM
|
</li>
<li>
ATM
</li>
</>
) : null}
{stratSub === "exit" ? (
<li>
/ SIM
LIVE
</li>
) : null}
{stratSub === "pace" ? (
<li>
LIVE / 1s
0.230
</li>
) : null}
</ul>
</RulesFold>
<div className="settings-actions">
<button className="btn" type="submit">
@@ -572,10 +625,6 @@ export default function SettingsPage() {
{tab === "runtime" ? (
<div className="card settings-card">
<p className="settings-lead">
SIM = LIVE = OKX / {" "}
<span className="mono">.env</span>OKX USDC USDT
</p>
{runtimeOk ? <div className="settings-ok">{runtimeOk}</div> : null}
{err && tab === "runtime" ? <div className="err">{err}</div> : null}
<form onSubmit={onSaveRuntime}>
@@ -595,15 +644,6 @@ export default function SettingsPage() {
<option value="SIM">SIM </option>
<option value="LIVE">LIVE </option>
</select>
<p className="settings-hint">
{runtime?.mode || "—"} · {runtime?.exchange || "—"} ·{" "}
{runtime?.mode === "LIVE"
? runtime.live_ready
? "LIVE 就绪"
: `未就绪(${runtime.live_ready_reason})`
: "SIM"}
</p>
</div>
</div>
</section>
@@ -697,13 +737,37 @@ export default function SettingsPage() {
onChange={(e) => setBnSecret(e.target.value)}
/>
</div>
<p className="settings-hint">
= LIVE
Passphrase
</p>
</div>
</section>
<RulesFold
open={runtimeRulesOpen}
onToggle={() => setRuntimeRulesOpen((v) => !v)}
>
<ul className="settings-rules-list">
<li>
SIM = LIVE =
OKX / {" "}
<span className="mono">.env</span>
OKX USDC USDT
</li>
<li>
{runtime?.mode || "—"} · {" "}
{runtime?.exchange || "—"} ·{" "}
{runtime?.mode === "LIVE"
? runtime.live_ready
? "LIVE 就绪"
: `未就绪(${runtime.live_ready_reason})`
: "SIM"}
</li>
<li>
= LIVE
Passphrase
</li>
</ul>
</RulesFold>
<div className="settings-actions">
<button className="btn" type="submit" disabled={loading}>
{loading ? "保存中…" : "保存模式与密钥"}
+54
View File
@@ -472,6 +472,60 @@ input {
line-height: 1.4;
}
.settings-rules {
margin: 4px 0 12px;
border: 1px solid var(--line);
border-radius: 8px;
background: var(--input);
}
.settings-rules-toggle {
appearance: none;
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
border: 0;
background: transparent;
color: var(--muted);
padding: 10px 12px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
text-align: left;
}
.settings-rules-toggle:hover {
color: var(--text);
}
.settings-rules.open .settings-rules-toggle {
color: var(--text);
border-bottom: 1px solid var(--line);
}
.settings-rules-chevron {
color: var(--muted);
font-size: 12px;
}
.settings-rules-body {
padding: 10px 12px 12px;
}
.settings-rules-list {
margin: 0;
padding-left: 18px;
color: var(--muted);
font-size: 12px;
line-height: 1.55;
}
.settings-rules-list li + li {
margin-top: 6px;
}
.settings-actions {
margin-top: 8px;
display: flex;