优化中控科技风界面:登录居中、浮盈配色、默认打开首个客户端。
总览改名期权持仓总览,内容区 1800 居中,去掉左上角仓库名。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -91,13 +91,13 @@ def login():
|
|||||||
if u == hub_username() and p == hub_password():
|
if u == hub_username() and p == hub_password():
|
||||||
session["logged_in"] = True
|
session["logged_in"] = True
|
||||||
session.permanent = True
|
session.permanent = True
|
||||||
nxt = (request.args.get("next") or request.form.get("next") or "/").strip() or "/"
|
nxt = (request.args.get("next") or request.form.get("next") or "/desk").strip() or "/desk"
|
||||||
if not nxt.startswith("/"):
|
if not nxt.startswith("/"):
|
||||||
nxt = "/"
|
nxt = "/desk"
|
||||||
return redirect(nxt)
|
return redirect(nxt)
|
||||||
flash("用户名或密码错误")
|
flash("用户名或密码错误")
|
||||||
if session.get("logged_in"):
|
if session.get("logged_in"):
|
||||||
return redirect("/")
|
return redirect("/desk")
|
||||||
return render_template("login.html")
|
return render_template("login.html")
|
||||||
|
|
||||||
|
|
||||||
@@ -195,7 +195,11 @@ def settings_page():
|
|||||||
@app.route("/desk")
|
@app.route("/desk")
|
||||||
@login_required
|
@login_required
|
||||||
def desk():
|
def desk():
|
||||||
|
instances = list_instances(enabled_only=True)
|
||||||
iid = request.args.get("id")
|
iid = request.args.get("id")
|
||||||
|
# 未指定客户端时默认打开第一个
|
||||||
|
if (not iid or not str(iid).isdigit()) and instances:
|
||||||
|
return redirect(url_for("desk", id=instances[0]["id"]))
|
||||||
inst = None
|
inst = None
|
||||||
open_url = ""
|
open_url = ""
|
||||||
if iid and str(iid).isdigit():
|
if iid and str(iid).isdigit():
|
||||||
@@ -209,7 +213,7 @@ def desk():
|
|||||||
)
|
)
|
||||||
return render_template(
|
return render_template(
|
||||||
"desk.html",
|
"desk.html",
|
||||||
instances=list_instances(enabled_only=True),
|
instances=instances,
|
||||||
current=inst,
|
current=inst,
|
||||||
open_url=open_url,
|
open_url=open_url,
|
||||||
)
|
)
|
||||||
|
|||||||
+203
-65
@@ -1,65 +1,186 @@
|
|||||||
|
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600;700&family=Orbitron:wght@500;600&display=swap");
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bg: #0f1219;
|
--bg: #070b14;
|
||||||
--panel: #171c27;
|
--bg-2: #0c1424;
|
||||||
--line: #2a3348;
|
--panel: rgba(16, 24, 40, 0.82);
|
||||||
--text: #e8ecf5;
|
--panel-solid: #101828;
|
||||||
--muted: #8b95ab;
|
--line: rgba(56, 189, 248, 0.22);
|
||||||
--accent: #6c5ce7;
|
--line-strong: rgba(56, 189, 248, 0.45);
|
||||||
--ok: #3dd68c;
|
--text: #e8f1ff;
|
||||||
--bad: #ff6b6b;
|
--muted: #8aa0b8;
|
||||||
|
--accent: #22d3ee;
|
||||||
|
--accent-2: #38bdf8;
|
||||||
|
--accent-deep: #0ea5e9;
|
||||||
|
--ok: #34d399;
|
||||||
|
--bad: #fb7185;
|
||||||
|
--shadow: 0 0 0 1px rgba(56, 189, 248, 0.08), 0 18px 50px rgba(0, 0, 0, 0.45);
|
||||||
|
--radius: 14px;
|
||||||
|
--font: "IBM Plex Sans", "Segoe UI", sans-serif;
|
||||||
|
--font-display: "Orbitron", "IBM Plex Sans", sans-serif;
|
||||||
}
|
}
|
||||||
* { box-sizing: border-box; }
|
* { box-sizing: border-box; }
|
||||||
|
html, body { min-height: 100%; }
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-family: "Segoe UI", system-ui, sans-serif;
|
font-family: var(--font);
|
||||||
background: var(--bg);
|
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
|
background:
|
||||||
|
radial-gradient(1200px 600px at 12% -10%, rgba(14, 165, 233, 0.18), transparent 55%),
|
||||||
|
radial-gradient(900px 500px at 90% 10%, rgba(34, 211, 238, 0.1), transparent 50%),
|
||||||
|
linear-gradient(180deg, var(--bg-2), var(--bg) 40%, #05080f);
|
||||||
|
background-attachment: fixed;
|
||||||
}
|
}
|
||||||
a { color: #9ec1ff; text-decoration: none; }
|
body::before {
|
||||||
|
content: "";
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: 0.35;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(56, 189, 248, 0.06) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(56, 189, 248, 0.06) 1px, transparent 1px);
|
||||||
|
background-size: 48px 48px;
|
||||||
|
mask-image: radial-gradient(ellipse at center, #000 35%, transparent 80%);
|
||||||
|
}
|
||||||
|
body > * { position: relative; z-index: 1; }
|
||||||
|
a { color: var(--accent-2); text-decoration: none; }
|
||||||
|
a:hover { color: #7dd3fc; }
|
||||||
|
|
||||||
.topbar {
|
.topbar {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: 10px 16px;
|
padding: 12px 20px;
|
||||||
border-bottom: 1px solid var(--line);
|
border-bottom: 1px solid var(--line);
|
||||||
background: #12161f;
|
background: rgba(8, 14, 26, 0.75);
|
||||||
|
backdrop-filter: blur(12px);
|
||||||
}
|
}
|
||||||
.topbar nav a { margin-left: 14px; color: var(--muted); }
|
.topbar nav a {
|
||||||
.topbar nav a.active { color: #fff; }
|
margin-right: 16px;
|
||||||
.brand { font-weight: 700; }
|
color: var(--muted);
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.02em;
|
||||||
|
}
|
||||||
|
.topbar nav a:last-child { margin-right: 0; }
|
||||||
|
.topbar nav a.active {
|
||||||
|
color: var(--accent);
|
||||||
|
text-shadow: 0 0 18px rgba(34, 211, 238, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
.main { padding: 16px; max-width: 1200px; margin: 0 auto; }
|
.main { padding: 16px; max-width: 1200px; margin: 0 auto; }
|
||||||
/* 总览/工作台:带鱼屏两侧留边,内容区限宽居中 */
|
|
||||||
body.page-desk .main,
|
body.page-desk .main,
|
||||||
body.page-dashboard .main {
|
body.page-dashboard .main {
|
||||||
max-width: 1680px;
|
max-width: 1800px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 12px clamp(16px, 3vw, 48px) 20px;
|
padding: 12px clamp(16px, 3vw, 48px) 20px;
|
||||||
}
|
}
|
||||||
|
body.page-login {
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
body.page-login .main {
|
||||||
|
max-width: none;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
.page-head { display: flex; align-items: center; gap: 12px; }
|
.page-head { display: flex; align-items: center; gap: 12px; }
|
||||||
|
.page-head h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 1.35rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
.muted { color: var(--muted); font-size: 0.9rem; }
|
.muted { color: var(--muted); font-size: 0.9rem; }
|
||||||
.flash {
|
.flash {
|
||||||
background: #2a2140;
|
background: rgba(14, 165, 233, 0.12);
|
||||||
border: 1px solid #5b4a8a;
|
border: 1px solid var(--line-strong);
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 8px;
|
border-radius: 10px;
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* —— 登录 —— */
|
||||||
|
.login-wrap {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 420px;
|
||||||
}
|
}
|
||||||
.login-card {
|
.login-card {
|
||||||
max-width: 360px;
|
width: 100%;
|
||||||
margin: 10vh auto;
|
margin: 0;
|
||||||
background: var(--panel);
|
padding: 32px 28px 28px;
|
||||||
border: 1px solid var(--line);
|
border-radius: 18px;
|
||||||
border-radius: 12px;
|
background: linear-gradient(160deg, rgba(18, 32, 54, 0.92), rgba(10, 16, 28, 0.95));
|
||||||
padding: 24px;
|
border: 1px solid var(--line-strong);
|
||||||
|
box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.04);
|
||||||
|
backdrop-filter: blur(16px);
|
||||||
}
|
}
|
||||||
|
.login-card h1 {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 1.45rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.06em;
|
||||||
|
background: linear-gradient(90deg, #e0f2fe, var(--accent));
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
background-clip: text;
|
||||||
|
color: transparent;
|
||||||
|
}
|
||||||
|
.login-card .login-sub {
|
||||||
|
margin: 0 0 22px;
|
||||||
|
color: var(--muted);
|
||||||
|
font-size: 0.88rem;
|
||||||
|
line-height: 1.45;
|
||||||
|
}
|
||||||
|
.login-card .stack label {
|
||||||
|
display: block;
|
||||||
|
margin: 0 0 14px;
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: #b6c7da;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.login-card input {
|
||||||
|
margin-top: 6px;
|
||||||
|
padding: 11px 12px;
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid var(--line);
|
||||||
|
background: rgba(5, 10, 18, 0.85);
|
||||||
|
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||||
|
}
|
||||||
|
.login-card input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--accent);
|
||||||
|
box-shadow: 0 0 0 3px rgba(34, 211, 238, 0.15);
|
||||||
|
}
|
||||||
|
.login-card button[type="submit"] {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 8px;
|
||||||
|
padding: 12px 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
background: linear-gradient(90deg, var(--accent-deep), var(--accent));
|
||||||
|
color: #041018;
|
||||||
|
box-shadow: 0 8px 24px rgba(14, 165, 233, 0.28);
|
||||||
|
}
|
||||||
|
.login-card button[type="submit"]:hover {
|
||||||
|
filter: brightness(1.05);
|
||||||
|
}
|
||||||
|
|
||||||
.stack label, .form-grid label { display: block; margin: 8px 0; }
|
.stack label, .form-grid label { display: block; margin: 8px 0; }
|
||||||
input[type="text"], input[type="password"], input:not([type]) {
|
input[type="text"], input[type="password"], input:not([type]) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px 10px;
|
padding: 8px 10px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
background: #0d1017;
|
background: #0a1220;
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
button, .btn {
|
button, .btn {
|
||||||
@@ -68,17 +189,21 @@ button, .btn {
|
|||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 0;
|
border: 0;
|
||||||
background: var(--accent);
|
background: linear-gradient(90deg, var(--accent-deep), #06b6d4);
|
||||||
color: #fff;
|
color: #041018;
|
||||||
|
font-weight: 600;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.btn-danger { background: #8b3a3a; }
|
.btn:hover, button:hover { filter: brightness(1.06); }
|
||||||
|
.btn-danger { background: #9f1239; color: #fff; }
|
||||||
.panel {
|
.panel {
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 12px;
|
border-radius: var(--radius);
|
||||||
padding: 14px;
|
padding: 14px;
|
||||||
margin: 14px 0;
|
margin: 14px 0;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
.form-grid {
|
.form-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -92,8 +217,10 @@ button, .btn {
|
|||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 12px;
|
border-radius: var(--radius);
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
.overview-table {
|
.overview-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -103,15 +230,16 @@ button, .btn {
|
|||||||
.overview-table th,
|
.overview-table th,
|
||||||
.overview-table td {
|
.overview-table td {
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border-bottom: 1px solid var(--line);
|
border-bottom: 1px solid rgba(56, 189, 248, 0.12);
|
||||||
text-align: left;
|
text-align: left;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
.overview-table th {
|
.overview-table th {
|
||||||
color: var(--muted);
|
color: var(--accent-2);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
background: #12161f;
|
background: rgba(8, 16, 30, 0.9);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
}
|
}
|
||||||
.overview-table tr:last-child td { border-bottom: 0; }
|
.overview-table tr:last-child td { border-bottom: 0; }
|
||||||
.overview-table .status-on { color: var(--ok); }
|
.overview-table .status-on { color: var(--ok); }
|
||||||
@@ -134,13 +262,15 @@ button, .btn {
|
|||||||
.card {
|
.card {
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 12px;
|
border-radius: var(--radius);
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
.card .status-on { color: var(--ok); }
|
.card .status-on { color: var(--ok); }
|
||||||
.card .status-off { color: var(--bad); }
|
.card .status-off { color: var(--bad); }
|
||||||
.card table { width: 100%; font-size: 0.8rem; border-collapse: collapse; }
|
.card table { width: 100%; font-size: 0.8rem; border-collapse: collapse; }
|
||||||
.card td, .card th { border-bottom: 1px solid var(--line); padding: 4px 2px; text-align: left; }
|
.card td, .card th { border-bottom: 1px solid var(--line); padding: 4px 2px; text-align: left; }
|
||||||
|
|
||||||
.desk {
|
.desk {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 220px minmax(0, 1fr);
|
grid-template-columns: 220px minmax(0, 1fr);
|
||||||
@@ -155,10 +285,12 @@ button, .btn {
|
|||||||
.desk-side {
|
.desk-side {
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 12px;
|
border-radius: var(--radius);
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
}
|
}
|
||||||
.desk-side-head {
|
.desk-side-head {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -169,8 +301,11 @@ button, .btn {
|
|||||||
}
|
}
|
||||||
.desk-side-title {
|
.desk-side-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 1rem;
|
font-size: 0.95rem;
|
||||||
|
font-family: var(--font-display);
|
||||||
|
letter-spacing: 0.04em;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
color: var(--accent-2);
|
||||||
}
|
}
|
||||||
.desk-side-toggle {
|
.desk-side-toggle {
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
@@ -180,34 +315,24 @@ button, .btn {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
background: #12161f;
|
background: rgba(8, 16, 30, 0.9);
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.desk-side-toggle:hover { border-color: var(--accent); }
|
.desk-side-toggle:hover { border-color: var(--accent); color: var(--accent); }
|
||||||
.desk-side-toggle--bar {
|
.desk-side-toggle--bar { display: none; }
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.desk.is-side-collapsed .desk-side-title,
|
.desk.is-side-collapsed .desk-side-title,
|
||||||
.desk.is-side-collapsed .desk-list-name,
|
.desk.is-side-collapsed .desk-list-name,
|
||||||
.desk.is-side-collapsed .desk-list-empty {
|
.desk.is-side-collapsed .desk-list-empty { display: none; }
|
||||||
display: none;
|
.desk.is-side-collapsed .desk-side { padding: 8px 6px; }
|
||||||
}
|
|
||||||
.desk.is-side-collapsed .desk-side {
|
|
||||||
padding: 8px 6px;
|
|
||||||
}
|
|
||||||
.desk.is-side-collapsed .desk-side-head {
|
.desk.is-side-collapsed .desk-side-head {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
.desk.is-side-collapsed .desk-side-toggle {
|
.desk.is-side-collapsed .desk-side-toggle { transform: rotate(180deg); }
|
||||||
transform: rotate(180deg);
|
.desk.is-side-collapsed .desk-list { display: none; }
|
||||||
}
|
|
||||||
.desk.is-side-collapsed .desk-list {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.desk.is-side-collapsed .desk-side-toggle--bar {
|
.desk.is-side-collapsed .desk-side-toggle--bar {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -217,12 +342,22 @@ button, .btn {
|
|||||||
.desk-list li { margin: 6px 0; }
|
.desk-list li { margin: 6px 0; }
|
||||||
.desk-list li a {
|
.desk-list li a {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 6px 8px;
|
padding: 7px 9px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.desk-list li a:hover {
|
||||||
|
background: rgba(34, 211, 238, 0.08);
|
||||||
|
color: #fff;
|
||||||
|
border-color: rgba(34, 211, 238, 0.2);
|
||||||
|
}
|
||||||
|
.desk-list li.active a {
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
background: rgba(34, 211, 238, 0.16);
|
||||||
|
border-color: rgba(34, 211, 238, 0.35);
|
||||||
}
|
}
|
||||||
.desk-list li a:hover { background: rgba(108, 92, 231, 0.12); color: #fff; }
|
|
||||||
.desk-list li.active a { color: #fff; font-weight: 600; background: rgba(108, 92, 231, 0.22); }
|
|
||||||
.desk-main { display: flex; flex-direction: column; min-height: calc(100vh - 70px); min-width: 0; }
|
.desk-main { display: flex; flex-direction: column; min-height: calc(100vh - 70px); min-width: 0; }
|
||||||
.desk-toolbar {
|
.desk-toolbar {
|
||||||
display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
|
display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
|
||||||
@@ -233,8 +368,9 @@ button, .btn {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: calc(100vh - 130px);
|
min-height: calc(100vh - 130px);
|
||||||
border: 1px solid var(--line);
|
border: 1px solid var(--line);
|
||||||
border-radius: 10px;
|
border-radius: var(--radius);
|
||||||
background: #000;
|
background: #000;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
}
|
}
|
||||||
.empty { padding: 40px; color: var(--muted); }
|
.empty { padding: 40px; color: var(--muted); }
|
||||||
.settings-card { max-width: 480px; }
|
.settings-card { max-width: 480px; }
|
||||||
@@ -243,17 +379,19 @@ input.readonly {
|
|||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
.pnl-up { color: var(--ok); font-weight: 600; }
|
||||||
|
.pnl-down { color: var(--bad); font-weight: 600; }
|
||||||
|
.pnl-flat { color: var(--muted); }
|
||||||
|
|
||||||
@media (max-width: 800px) {
|
@media (max-width: 800px) {
|
||||||
.desk,
|
.desk,
|
||||||
.desk.is-side-collapsed {
|
.desk.is-side-collapsed { grid-template-columns: 1fr; }
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
.desk-side-toggle--bar { display: none !important; }
|
.desk-side-toggle--bar { display: none !important; }
|
||||||
}
|
}
|
||||||
@media (min-width: 2000px) {
|
@media (min-width: 2000px) {
|
||||||
body.page-desk .main,
|
body.page-desk .main,
|
||||||
body.page-dashboard .main {
|
body.page-dashboard .main {
|
||||||
max-width: 1760px;
|
max-width: 1800px;
|
||||||
padding-left: clamp(32px, 6vw, 96px);
|
padding-left: clamp(32px, 6vw, 96px);
|
||||||
padding-right: clamp(32px, 6vw, 96px);
|
padding-right: clamp(32px, 6vw, 96px);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -6,6 +6,16 @@
|
|||||||
return (n > 0 ? "+" : "") + n.toFixed(2) + " U";
|
return (n > 0 ? "+" : "") + n.toFixed(2) + " U";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function pnlClass(v) {
|
||||||
|
const n = Number(v);
|
||||||
|
if (!Number.isFinite(n) || n === 0) return "pnl-flat";
|
||||||
|
return n > 0 ? "pnl-up" : "pnl-down";
|
||||||
|
}
|
||||||
|
|
||||||
|
function fmtPnlHtml(v) {
|
||||||
|
return '<span class="' + pnlClass(v) + '">' + escapeHtml(fmtPnl(v)) + "</span>";
|
||||||
|
}
|
||||||
|
|
||||||
function escapeHtml(s) {
|
function escapeHtml(s) {
|
||||||
return String(s)
|
return String(s)
|
||||||
.replace(/&/g, "&")
|
.replace(/&/g, "&")
|
||||||
@@ -20,8 +30,7 @@
|
|||||||
const items = list.slice(0, 8).map(function (p) {
|
const items = list.slice(0, 8).map(function (p) {
|
||||||
const id = escapeHtml(p.inst_id || "");
|
const id = escapeHtml(p.inst_id || "");
|
||||||
const sheets = escapeHtml(String(p.sheets != null ? p.sheets : "—"));
|
const sheets = escapeHtml(String(p.sheets != null ? p.sheets : "—"));
|
||||||
const pnl = escapeHtml(fmtPnl(p.pnl_usdt));
|
return "<li>" + id + " · " + sheets + "张 · " + fmtPnlHtml(p.pnl_usdt) + "</li>";
|
||||||
return "<li>" + id + " · " + sheets + "张 · " + pnl + "</li>";
|
|
||||||
});
|
});
|
||||||
const more =
|
const more =
|
||||||
list.length > 8
|
list.length > 8
|
||||||
@@ -59,7 +68,7 @@
|
|||||||
escapeHtml(inst.mode || "—") +
|
escapeHtml(inst.mode || "—") +
|
||||||
"</td>" +
|
"</td>" +
|
||||||
"<td>" +
|
"<td>" +
|
||||||
escapeHtml(fmtPnl(pnl)) +
|
fmtPnlHtml(pnl) +
|
||||||
"</td>" +
|
"</td>" +
|
||||||
"<td>" +
|
"<td>" +
|
||||||
positionSummary(brief) +
|
positionSummary(brief) +
|
||||||
|
|||||||
+1
-2
@@ -6,10 +6,9 @@
|
|||||||
<title>{% block title %}期权中控{% endblock %}</title>
|
<title>{% block title %}期权中控{% endblock %}</title>
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='hub.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<body class="{% if request.path.startswith('/desk') %}page-desk{% elif request.path == '/' %}page-dashboard{% endif %}">
|
<body class="{% if request.path.startswith('/login') %}page-login{% elif request.path.startswith('/desk') %}page-desk{% elif request.path == '/' %}page-dashboard{% endif %}">
|
||||||
{% if session.get('logged_in') %}
|
{% if session.get('logged_in') %}
|
||||||
<header class="topbar">
|
<header class="topbar">
|
||||||
<div class="brand">crypto_okx_hub</div>
|
|
||||||
<nav>
|
<nav>
|
||||||
<a href="/" class="{% if request.path == '/' %}active{% endif %}">总览</a>
|
<a href="/" class="{% if request.path == '/' %}active{% endif %}">总览</a>
|
||||||
<a href="/instances" class="{% if request.path.startswith('/instances') %}active{% endif %}">实例</a>
|
<a href="/instances" class="{% if request.path.startswith('/instances') %}active{% endif %}">实例</a>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% block title %}总览 · 期权中控{% endblock %}
|
{% block title %}总览 · 期权中控{% endblock %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<section class="page-head">
|
<section class="page-head">
|
||||||
<h1>多机持仓总览</h1>
|
<h1>期权持仓总览</h1>
|
||||||
<button type="button" class="btn" id="btn-refresh">刷新</button>
|
<button type="button" class="btn" id="btn-refresh">刷新</button>
|
||||||
</section>
|
</section>
|
||||||
<p class="muted" id="overview-status">加载中…</p>
|
<p class="muted" id="overview-status">加载中…</p>
|
||||||
|
|||||||
+15
-9
@@ -1,13 +1,19 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
{% block title %}登录 · 期权中控{% endblock %}
|
{% block title %}登录 · 期权中控{% endblock %}
|
||||||
{% block body %}
|
{% block body %}
|
||||||
<section class="login-card">
|
<div class="login-wrap">
|
||||||
<h1>期权中控登录</h1>
|
<section class="login-card">
|
||||||
<p class="muted">关联客户端仓库 crypto_okx · 本仓不下单</p>
|
<h1>期权中控</h1>
|
||||||
<form method="post" class="stack">
|
<p class="login-sub">多机期权持仓总览 · 内嵌打开客户端 · 本仓不下单</p>
|
||||||
<label>用户名 <input name="username" autocomplete="username" required></label>
|
<form method="post" class="stack" autocomplete="on">
|
||||||
<label>密码 <input type="password" name="password" autocomplete="current-password" required></label>
|
<label>用户名
|
||||||
<button type="submit">登录</button>
|
<input name="username" autocomplete="username" required placeholder="admin">
|
||||||
</form>
|
</label>
|
||||||
</section>
|
<label>密码
|
||||||
|
<input type="password" name="password" autocomplete="current-password" required placeholder="••••••••">
|
||||||
|
</label>
|
||||||
|
<button type="submit">登 录</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
Reference in New Issue
Block a user