深色浅色主题切换;去掉新浪行情徽章;科技感卡片样式

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-06-15 13:04:48 +08:00
parent a35a08d2f6
commit db2443273f
8 changed files with 418 additions and 102 deletions
+36
View File
@@ -0,0 +1,36 @@
(function () {
var KEY = 'qihuo-theme';
function apply(theme) {
document.documentElement.setAttribute('data-theme', theme);
try {
localStorage.setItem(KEY, theme);
} catch (e) { /* ignore */ }
var btn = document.getElementById('theme-toggle');
if (btn) {
btn.setAttribute('data-active', theme);
btn.setAttribute('aria-label', theme === 'light' ? '切换到深色' : '切换到浅色');
}
}
var saved = null;
try {
saved = localStorage.getItem(KEY);
} catch (e) { /* ignore */ }
if (saved === 'light' || saved === 'dark') {
apply(saved);
} else {
var prefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;
apply(prefersLight ? 'light' : 'dark');
}
document.addEventListener('DOMContentLoaded', function () {
var btn = document.getElementById('theme-toggle');
if (!btn) return;
btn.addEventListener('click', function () {
var cur = document.documentElement.getAttribute('data-theme') || 'dark';
apply(cur === 'dark' ? 'light' : 'dark');
});
});
})();
+247 -54
View File
@@ -4,24 +4,178 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}国内期货监控系统{% endblock %}</title>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<style>
:root,[data-theme="dark"]{
--bg-page:#07070d;
--bg-grid:rgba(76,194,255,.035);
--border-header:#1a1a28;
--text-primary:#eaeaea;
--text-title:#ffffff;
--text-muted:#8a8a9e;
--text-label:#b4b4e8;
--accent:#4cc2ff;
--accent-2:#7b42ff;
--card-bg:rgba(14,14,22,.88);
--card-border:rgba(76,194,255,.18);
--card-glow:rgba(76,194,255,.07);
--card-inner:#161625;
--input-bg:#1a1a29;
--input-border:#2e2e45;
--nav-bg:#161625;
--nav-border:#2a2a40;
--nav-hover:#1e2533;
--nav-active:#2d5aa8;
--nav-active-border:#3d6ec4;
--list-item-bg:rgba(22,22,37,.75);
--table-border:#242435;
--profit:#4cd97f;
--profit-bg:#1e332f;
--loss:#ff6666;
--loss-bg:#331e24;
--dir-bg:#1e2533;
--planned-bg:#29241e;
--planned-text:#eac147;
--expired-bg:#2a2a35;
--expired-text:#999;
--flash-bg:#1e2533;
--flash-text:#4cc2ff;
--modal-mask:rgba(0,0,0,.72);
--danger:#ff6666;
--shadow-card:0 8px 32px rgba(0,0,0,.35),inset 0 1px 0 rgba(255,255,255,.05);
--calc-bg:#151520;
--toggle-bg:#161625;
--toggle-border:#2a2a40;
}
[data-theme="light"]{
--bg-page:#eef2f7;
--bg-grid:rgba(37,99,235,.05);
--border-header:#d1dae6;
--text-primary:#1a2233;
--text-title:#0f172a;
--text-muted:#5c6578;
--text-label:#1d4ed8;
--accent:#2563eb;
--accent-2:#6366f1;
--card-bg:rgba(255,255,255,.94);
--card-border:rgba(37,99,235,.22);
--card-glow:rgba(37,99,235,.06);
--card-inner:#f1f5f9;
--input-bg:#ffffff;
--input-border:#b8c5d6;
--nav-bg:#ffffff;
--nav-border:#c5d0dc;
--nav-hover:#eef2f7;
--nav-active:#2563eb;
--nav-active-border:#2563eb;
--list-item-bg:#f1f5f9;
--table-border:#e2e8f0;
--profit:#15803d;
--profit-bg:#dcfce7;
--loss:#dc2626;
--loss-bg:#fee2e2;
--dir-bg:#dbeafe;
--planned-bg:#fef9c3;
--planned-text:#a16207;
--expired-bg:#f1f5f9;
--expired-text:#64748b;
--flash-bg:#dbeafe;
--flash-text:#1d4ed8;
--modal-mask:rgba(15,23,42,.45);
--danger:#dc2626;
--shadow-card:0 8px 28px rgba(15,23,42,.08),inset 0 1px 0 rgba(255,255,255,.95);
--calc-bg:#eef2ff;
--toggle-bg:#ffffff;
--toggle-border:#c5d0dc;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#0a0a10;color:#eaeaea;min-height:100vh}
body{
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
background:var(--bg-page);
background-image:
radial-gradient(ellipse 80% 50% at 50% -20%,var(--card-glow),transparent),
linear-gradient(var(--bg-grid) 1px,transparent 1px),
linear-gradient(90deg,var(--bg-grid) 1px,transparent 1px);
background-size:100% 100%,28px 28px,28px 28px;
color:var(--text-primary);
min-height:100vh;
transition:background .25s,color .25s;
}
.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 #1a1a28;position:relative}
.site-title{font-size:1.75rem;font-weight:700;color:#fff;margin-bottom:.55rem;line-height:1.3}
.site-badge{display:inline-block;padding:.22rem .85rem;border-radius:999px;border:1px solid #2d6a4f;background:#0d2818;color:#4cd97f;font-size:.75rem;margin-bottom:1.15rem}
.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}
.header-tools{position:absolute;top:1rem;left:1.5rem;display:flex;gap:.5rem;align-items:center}
.theme-toggle{
display:flex;align-items:center;gap:.35rem;
padding:.4rem .75rem;border-radius:8px;
border:1px solid var(--toggle-border);
background:var(--toggle-bg);
color:var(--text-primary);
font-size:.78rem;cursor:pointer;
transition:.2s;
}
.theme-toggle:hover{border-color:var(--accent);color:var(--accent)}
.theme-toggle .icon-light,.theme-toggle .icon-dark{display:none}
[data-theme="dark"] .theme-toggle .icon-light{display:inline}
[data-theme="light"] .theme-toggle .icon-dark{display:inline}
.site-nav{display:flex;justify-content:center;gap:.45rem;flex-wrap:wrap}
.site-nav a{padding:.55rem 1.15rem;border-radius:8px;border:1px solid #2a2a40;background:#161625;color:#e8e8f0;text-decoration:none;font-size:.88rem;transition:.2s;white-space:nowrap}
.site-nav a:hover{background:#1e2533;border-color:#3a3a55;color:#fff}
.site-nav a.active{background:#2d5aa8;border-color:#3d6ec4;color:#fff}
.user-bar{position:absolute;top:1rem;right:1.5rem;font-size:.8rem;color:#888;white-space:nowrap}
.user-bar a{color:#ff6666;text-decoration:none;margin-left:.5rem}
.site-nav a{
padding:.55rem 1.15rem;border-radius:8px;
border:1px solid var(--nav-border);
background:var(--nav-bg);
color:var(--text-primary);
text-decoration:none;font-size:.88rem;
transition:.2s;white-space:nowrap;
}
.site-nav a:hover{background:var(--nav-hover);border-color:var(--accent);color:var(--text-title)}
.site-nav a.active{background:var(--nav-active);border-color:var(--nav-active-border);color:#fff}
.user-bar{position:absolute;top:1rem;right:1.5rem;font-size:.8rem;color:var(--text-muted);white-space:nowrap}
.user-bar a{color:var(--danger);text-decoration:none;margin-left:.5rem}
.main{padding:1.5rem}
.flash{padding:1rem;background:#1e2533;color:#4cc2ff;border-radius:10px;margin-bottom:1.5rem;text-align:center}
.card{background:#12121a;border-radius:16px;padding:1.5rem;border:1px solid #242435;margin-bottom:1.5rem}
.card h2{font-size:1.15rem;margin-bottom:1rem;color:#c4c4ff;display:flex;align-items:center;gap:.5rem}
.card h2:before{content:"";width:4px;height:16px;background:#4cc2ff;border-radius:2px}
.text-muted{color:var(--text-muted)}
.text-label{color:var(--text-label)}
.text-accent{color:var(--accent)}
.text-profit{color:var(--profit)}
.text-loss{color:var(--loss)}
.section-label{font-size:.9rem;color:var(--text-label);margin:.75rem 0 .5rem}
.empty-hint{color:var(--text-muted);padding:.75rem;font-size:.85rem}
.flash{padding:1rem;background:var(--flash-bg);color:var(--flash-text);border-radius:10px;margin-bottom:1.5rem;text-align:center;border:1px solid var(--card-border)}
.card{
background:var(--card-bg);
border-radius:16px;padding:1.5rem;
border:1px solid var(--card-border);
margin-bottom:1.5rem;
position:relative;overflow:hidden;
box-shadow:var(--shadow-card);
backdrop-filter:blur(10px);
transition:background .25s,border-color .25s,box-shadow .25s;
}
.card::before{
content:"";position:absolute;inset:0;
background:linear-gradient(135deg,var(--card-glow) 0%,transparent 55%);
pointer-events:none;
}
.card::after{
content:"";position:absolute;top:0;left:12%;right:12%;height:1px;
background:linear-gradient(90deg,transparent,var(--accent),var(--accent-2),transparent);
opacity:.55;pointer-events:none;
}
.card-corner{
position:absolute;width:18px;height:18px;pointer-events:none;z-index:0;
border-color:var(--accent);opacity:.35;
}
.card-corner.tl{top:10px;left:10px;border-top:2px solid;border-left:2px solid}
.card-corner.br{bottom:10px;right:10px;border-bottom:2px solid;border-right:2px solid}
.card > *{position:relative;z-index:1}
.card h2{
font-size:1.15rem;margin-bottom:1rem;color:var(--text-label);
display:flex;align-items:center;gap:.5rem;
}
.card h2:before{
content:"";width:4px;height:16px;
background:linear-gradient(180deg,var(--accent),var(--accent-2));
border-radius:2px;box-shadow:0 0 8px var(--card-glow);
}
.form-row{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem;align-items:center}
.form-compact{display:flex;flex-direction:column;gap:.5rem;margin-bottom:1rem}
.form-compact .form-line{display:grid;gap:.5rem;align-items:center}
@@ -34,15 +188,15 @@
.form-compact input,.form-compact select{padding:.55rem .7rem;font-size:.85rem;border-radius:8px}
.form-compact .symbol-selected{font-size:.7rem;margin-top:2px}
.form-compact button.btn-primary{padding:.55rem 1.5rem;font-size:.85rem;white-space:nowrap}
.form-compact-review input.calc-readonly{color:#4cc2ff;background:#151520;font-size:.82rem}
.form-compact-review input.calc-readonly{color:var(--accent);background:var(--calc-bg);font-size:.82rem}
.form-compact-review textarea{min-height:44px;font-size:.85rem;padding:.45rem .65rem}
.form-compact-review .section-hint{font-size:.72rem;color:#888;margin:.25rem 0 .15rem}
.form-compact-review .section-hint{font-size:.72rem;color:var(--text-muted);margin:.25rem 0 .15rem}
.form-compact-review .tag-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.15rem .5rem;font-size:.75rem}
.form-compact-review .tag-grid label{display:flex;align-items:center;gap:.3rem;cursor:pointer;color:#bbb;white-space:nowrap}
.form-compact-review .tag-grid label{display:flex;align-items:center;gap:.3rem;cursor:pointer;color:var(--text-muted);white-space:nowrap}
.form-compact-review .tag-grid input{width:auto;flex-shrink:0}
.form-compact-review input[type="file"]{font-size:.72rem;padding:.4rem .5rem}
.form-compact-review .mini-field span{font-size:.65rem;color:#888;display:block;line-height:1;margin-bottom:2px}
.form-compact-review .kline-row label{display:flex;align-items:center;gap:.35rem;color:#bbb;white-space:nowrap}
.form-compact-review .mini-field span{font-size:.65rem;color:var(--text-muted);display:block;line-height:1;margin-bottom:2px}
.form-compact-review .kline-row label{display:flex;align-items:center;gap:.35rem;color:var(--text-muted);white-space:nowrap}
.form-compact-review .kline-row{display:grid;grid-template-columns:auto 1fr 1fr 1fr auto;gap:.5rem;align-items:end;font-size:.78rem}
.split-grid.records-split .card{min-height:auto}
.split-grid.records-split .card h2{font-size:1rem;margin-bottom:.5rem}
@@ -50,40 +204,64 @@
.page-title-sm{font-size:1.25rem;margin-bottom:.75rem}
.form-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:.75rem;margin-bottom:1rem}
.form-grid .full{grid-column:1/-1}
.field label{display:block;font-size:.8rem;color:#a9a9ff;margin-bottom:.35rem}
input,select,textarea,button{padding:.7rem 1rem;border-radius:10px;border:1px solid #2e2e45;background:#1a1a29;color:#fff;font-size:.9rem;outline:none;width:100%}
.field label{display:block;font-size:.8rem;color:var(--text-label);margin-bottom:.35rem}
input,select,textarea,button{
padding:.7rem 1rem;border-radius:10px;
border:1px solid var(--input-border);
background:var(--input-bg);color:var(--text-primary);
font-size:.9rem;outline:none;width:100%;
transition:border-color .2s,background .2s;
}
textarea{min-height:80px;resize:vertical}
input:focus,select:focus,textarea:focus{border-color:#4cc2ff}
button.btn-primary{background:linear-gradient(90deg,#4285f4,#7b42ff);border:none;cursor:pointer;color:#fff;width:auto}
input:focus,select:focus,textarea:focus{border-color:var(--accent)}
button.btn-primary{background:linear-gradient(90deg,var(--accent),var(--accent-2));border:none;cursor:pointer;color:#fff;width:auto}
button.btn-primary:hover{opacity:.9}
.list{display:flex;flex-direction:column;gap:.75rem}
.list-item{display:flex;justify-content:space-between;align-items:center;padding:1rem;background:#161625;border-radius:10px;gap:1rem;flex-wrap:wrap}
.btn-del{padding:.4rem .8rem;background:#291d2f;color:#ff6666;border-radius:8px;text-decoration:none;font-size:.85rem}
.list-item{
display:flex;justify-content:space-between;align-items:center;
padding:1rem;background:var(--list-item-bg);
border-radius:10px;gap:1rem;flex-wrap:wrap;
border:1px solid var(--card-border);
}
.btn-del{padding:.4rem .8rem;background:var(--loss-bg);color:var(--loss);border-radius:8px;text-decoration:none;font-size:.85rem}
table{width:100%;border-collapse:collapse}
th,td{padding:.85rem;text-align:left;border-bottom:1px solid #242435;font-size:.9rem}
th{color:#a9a9ff;white-space:nowrap}
th,td{padding:.85rem;text-align:left;border-bottom:1px solid var(--table-border);font-size:.9rem;color:var(--text-primary)}
th{color:var(--text-label);white-space:nowrap}
.badge{padding:.25rem .5rem;border-radius:6px;font-size:.75rem}
.badge.profit{background:#1e332f;color:#4cd97f}
.badge.loss{background:#331e24;color:#ff6666}
.badge.dir{background:#1e2533;color:#4cc2ff}
.badge.planned{background:#29241e;color:#eac147}
.badge.active{background:#1e332f;color:#4cd97f}
.badge.expired{background:#2a2a35;color:#999}
.badge.profit{background:var(--profit-bg);color:var(--profit)}
.badge.loss{background:var(--loss-bg);color:var(--loss)}
.badge.dir{background:var(--dir-bg);color:var(--accent)}
.badge.planned{background:var(--planned-bg);color:var(--planned-text)}
.badge.active{background:var(--profit-bg);color:var(--profit)}
.badge.expired{background:var(--expired-bg);color:var(--expired-text)}
.stat-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem;margin-bottom:1.5rem}
.stat-item{background:#161625;padding:1rem;border-radius:12px;text-align:center}
.stat-item .label{font-size:.8rem;color:#999}
.stat-item .value{font-size:1.4rem;font-weight:600;color:#fff;margin-top:.25rem}
.stat-item{
background:var(--card-inner);padding:1rem;border-radius:12px;text-align:center;
border:1px solid var(--card-border);position:relative;overflow:hidden;
}
.stat-item::before{
content:"";position:absolute;top:0;left:0;right:0;height:2px;
background:linear-gradient(90deg,var(--accent),var(--accent-2));opacity:.5;
}
.stat-item .label{font-size:.8rem;color:var(--text-muted)}
.stat-item .value{font-size:1.4rem;font-weight:600;color:var(--text-title);margin-top:.25rem}
.symbol-wrap{position:relative}
.symbol-dropdown{position:absolute;top:100%;left:0;right:0;background:#1a1a29;border:1px solid #2e2e45;border-radius:10px;margin-top:4px;z-index:100;max-height:240px;overflow-y:auto;display:none}
.symbol-dropdown{
position:absolute;top:100%;left:0;right:0;
background:var(--input-bg);border:1px solid var(--input-border);
border-radius:10px;margin-top:4px;z-index:100;
max-height:240px;overflow-y:auto;display:none;
box-shadow:var(--shadow-card);
}
.symbol-dropdown.show{display:block}
.symbol-option{padding:.65rem 1rem;cursor:pointer;font-size:.85rem;border-bottom:1px solid #242435}
.symbol-option:hover{background:#242435}
.symbol-option .sub{font-size:.75rem;color:#888;margin-top:2px}
.symbol-selected{font-size:.75rem;color:#4cc2ff;margin-top:4px}
.symbol-option{padding:.65rem 1rem;cursor:pointer;font-size:.85rem;border-bottom:1px solid var(--table-border)}
.symbol-option:hover{background:var(--list-item-bg)}
.symbol-option .sub{font-size:.75rem;color:var(--text-muted);margin-top:2px}
.symbol-selected{font-size:.75rem;color:var(--accent);margin-top:4px}
.check-row{display:flex;flex-wrap:wrap;gap:1rem;margin:.75rem 0}
.check-row label{display:flex;align-items:center;gap:.4rem;font-size:.85rem;color:#ccc;cursor:pointer}
.check-row label{display:flex;align-items:center;gap:.4rem;font-size:.85rem;color:var(--text-muted);cursor:pointer}
.check-row input{width:auto}
.hint{font-size:.78rem;color:#888;line-height:1.5;margin-top:.5rem}
.hint{font-size:.78rem;color:var(--text-muted);line-height:1.5;margin-top:.5rem}
.filter-row{display:flex;gap:.75rem;flex-wrap:wrap;align-items:flex-end;margin-bottom:1rem}
.filter-row .field{width:auto;min-width:140px}
.filter-row button{width:auto}
@@ -92,26 +270,36 @@
.split-grid .card-body{flex:1;overflow:auto}
.card-scroll{max-height:420px;overflow-y:auto}
.preset-tabs{display:flex;gap:.5rem;flex-wrap:wrap;margin-bottom:1rem}
.preset-tabs a{padding:.45rem .85rem;border-radius:8px;border:1px solid #2e2e45;color:#a9a9c4;text-decoration:none;font-size:.85rem}
.preset-tabs a.active,.preset-tabs a:hover{background:#1e2533;color:#4cc2ff;border-color:#4cc2ff}
.btn-link{color:#4cc2ff;cursor:pointer;font-size:.85rem;background:none;border:none;padding:0}
.preset-tabs a{
padding:.45rem .85rem;border-radius:8px;
border:1px solid var(--input-border);
color:var(--text-muted);text-decoration:none;font-size:.85rem;
}
.preset-tabs a.active,.preset-tabs a:hover{background:var(--dir-bg);color:var(--accent);border-color:var(--accent)}
.btn-link{color:var(--accent);cursor:pointer;font-size:.85rem;background:none;border:none;padding:0}
.btn-link:hover{text-decoration:underline}
.modal-mask{position:fixed;inset:0;background:rgba(0,0,0,.7);z-index:1000;display:none;align-items:center;justify-content:center;padding:1rem}
.modal-mask{position:fixed;inset:0;background:var(--modal-mask);z-index:1000;display:none;align-items:center;justify-content:center;padding:1rem}
.modal-mask.show{display:flex}
.modal-box{background:#12121a;border:1px solid #242435;border-radius:16px;max-width:900px;width:100%;max-height:90vh;overflow:auto;padding:1.5rem}
.modal-box h3{margin-bottom:1rem;color:#c4c4ff}
.modal-box{
background:var(--card-bg);border:1px solid var(--card-border);
border-radius:16px;max-width:900px;width:100%;
max-height:90vh;overflow:auto;padding:1.5rem;
box-shadow:var(--shadow-card);
}
.modal-box h3{margin-bottom:1rem;color:var(--text-label)}
.modal-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:.75rem;font-size:.9rem}
.modal-grid .item label{color:#888;font-size:.75rem;display:block}
.modal-grid .item div{margin-top:.2rem}
.modal-close{float:right;color:#888;cursor:pointer;font-size:1.2rem}
.calc-readonly{background:#161625;color:#4cc2ff}
.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-close{float:right;color:var(--text-muted);cursor:pointer;font-size:1.2rem}
.calc-readonly{background:var(--calc-bg);color:var(--accent)}
@media(max-width:1100px){
.split-grid{grid-template-columns:1fr}
.split-grid .card{min-height:auto}
}
@media(max-width:768px){
.site-header{padding:1.25rem .75rem 1rem}
.site-title{font-size:1.35rem}
.site-title{font-size:1.35rem;margin-bottom:.85rem}
.header-tools{position:static;justify-content:center;margin-bottom:.75rem}
.user-bar{position:static;text-align:center;margin-bottom:.75rem}
.site-nav{gap:.35rem}
.site-nav a{padding:.45rem .75rem;font-size:.82rem}
@@ -122,9 +310,14 @@
<body>
<div class="page-wrap">
<header class="site-header">
<div class="header-tools">
<button type="button" id="theme-toggle" class="theme-toggle" data-active="dark" aria-label="切换主题">
<span class="icon-light">浅色</span>
<span class="icon-dark">深色</span>
</button>
</div>
<div class="user-bar">{{ session.username or '用户' }}<a href="{{ url_for('logout') }}">退出</a></div>
<h1 class="site-title">国内期货 | 交易监控 + 复盘一体化</h1>
<div class="site-badge">新浪行情</div>
<nav class="site-nav">
<a href="{{ url_for('plans') }}" class="{% if request.endpoint == 'plans' %}active{% endif %}">开单计划</a>
<a href="{{ url_for('keys') }}" class="{% if request.endpoint == 'keys' %}active{% endif %}">关键位监控</a>
+3 -3
View File
@@ -34,7 +34,7 @@
<button type="submit" class="btn-primary">添加</button>
</div>
</form>
<h3 style="font-size:.9rem;color:#a9a9ff;margin:.75rem 0 .5rem">监控列表</h3>
<h3 class="section-label">监控列表</h3>
<div class="list card-scroll">
{% for k in keys %}
<div class="list-item" style="padding:.75rem;font-size:.85rem">
@@ -46,7 +46,7 @@
<a href="{{ url_for('del_key', pid=k.id) }}" class="btn-del" onclick="return confirm('移入历史?')"></a>
</div>
{% else %}
<div style="color:#888;padding:.75rem;font-size:.85rem">暂无监控</div>
<div class="empty-hint">暂无监控</div>
{% endfor %}
</div>
</div>
@@ -68,7 +68,7 @@
<td>{{ k.archived_at[:16] if k.archived_at else '' }}</td>
</tr>
{% else %}
<tr><td colspan="6" style="color:#888">暂无历史</td></tr>
<tr><td colspan="6" class="text-muted">暂无历史</td></tr>
{% endfor %}
</tbody>
</table>
+110 -24
View File
@@ -4,37 +4,123 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>系统登录</title>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<style>
:root,[data-theme="dark"]{
--bg-page:#07070d;
--card-bg:rgba(14,14,22,.92);
--card-border:rgba(76,194,255,.18);
--text-primary:#eaeaea;
--text-label:#b4b4e8;
--accent:#4cc2ff;
--accent-2:#7b42ff;
--input-bg:#1a1a29;
--input-border:#2e2e45;
--loss-bg:#331e24;
--loss:#ff6666;
--shadow:0 12px 40px rgba(0,0,0,.4);
--toggle-bg:#161625;
--toggle-border:#2a2a40;
}
[data-theme="light"]{
--bg-page:#eef2f7;
--card-bg:rgba(255,255,255,.96);
--card-border:rgba(37,99,235,.22);
--text-primary:#1a2233;
--text-label:#1d4ed8;
--accent:#2563eb;
--accent-2:#6366f1;
--input-bg:#ffffff;
--input-border:#b8c5d6;
--loss-bg:#fee2e2;
--loss:#dc2626;
--shadow:0 12px 32px rgba(15,23,42,.1);
--toggle-bg:#ffffff;
--toggle-border:#c5d0dc;
}
*{margin:0;padding:0;box-sizing:border-box}
body{background:#0a0a10;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;color:#fff}
.login-box{background:#12121a;padding:2.5rem;border-radius:16px;width:100%;max-width:400px;border:1px solid #242435;box-shadow:0 8px 24px rgba(0,0,0,.3)}
.login-box h2{margin-bottom:2rem;text-align:center;font-size:1.5rem;background:linear-gradient(90deg,#4cc2ff,#7b42ff);-webkit-background-clip:text;-webkit-text-fill-color:transparent}
body{
background:var(--bg-page);
font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
display:flex;align-items:center;justify-content:center;
min-height:100vh;color:var(--text-primary);
padding:1rem;
}
.login-wrap{width:100%;max-width:400px}
.theme-row{display:flex;justify-content:flex-end;margin-bottom:.75rem}
.theme-toggle{
padding:.4rem .75rem;border-radius:8px;
border:1px solid var(--toggle-border);
background:var(--toggle-bg);color:var(--text-primary);
font-size:.78rem;cursor:pointer;
}
.theme-toggle .icon-light,.theme-toggle .icon-dark{display:none}
[data-theme="dark"] .theme-toggle .icon-light{display:inline}
[data-theme="light"] .theme-toggle .icon-dark{display:inline}
.login-box{
background:var(--card-bg);
padding:2.5rem;border-radius:16px;
border:1px solid var(--card-border);
box-shadow:var(--shadow);
position:relative;overflow:hidden;
}
.login-box::after{
content:"";position:absolute;top:0;left:15%;right:15%;height:1px;
background:linear-gradient(90deg,transparent,var(--accent),var(--accent-2),transparent);
opacity:.6;
}
.login-box h2{
margin-bottom:2rem;text-align:center;font-size:1.5rem;
background:linear-gradient(90deg,var(--accent),var(--accent-2));
-webkit-background-clip:text;-webkit-text-fill-color:transparent;
}
.form-group{margin-bottom:1.25rem}
.form-group label{display:block;margin-bottom:.5rem;font-size:.9rem;color:#a9a9ff}
.form-group input{width:100%;padding:.85rem 1rem;border-radius:10px;border:1px solid #2e2e45;background:#1a1a29;color:#fff;font-size:.95rem;outline:none}
.form-group input:focus{border-color:#4cc2ff}
button{width:100%;padding:.9rem;border-radius:10px;border:none;background:linear-gradient(90deg,#4285f4,#7b42ff);color:#fff;font-size:1rem;font-weight:500;cursor:pointer}
.form-group label{display:block;margin-bottom:.5rem;font-size:.9rem;color:var(--text-label)}
.form-group input{
width:100%;padding:.85rem 1rem;border-radius:10px;
border:1px solid var(--input-border);
background:var(--input-bg);color:var(--text-primary);
font-size:.95rem;outline:none;
}
.form-group input:focus{border-color:var(--accent)}
button{
width:100%;padding:.9rem;border-radius:10px;border:none;
background:linear-gradient(90deg,var(--accent),var(--accent-2));
color:#fff;font-size:1rem;font-weight:500;cursor:pointer;
}
button:hover{opacity:.9}
.flash{padding:.8rem;margin-bottom:1rem;background:#331e24;color:#ff6666;border-radius:8px;text-align:center;font-size:.85rem}
.flash{
padding:.8rem;margin-bottom:1rem;
background:var(--loss-bg);color:var(--loss);
border-radius:8px;text-align:center;font-size:.85rem;
}
</style>
</head>
<body>
<div class="login-box">
<h2>期货监控系统</h2>
{% with messages = get_flashed_messages() %}
{% if messages %}<div class="flash">{{ messages[0] }}</div>{% endif %}
{% endwith %}
<form method="POST">
<div class="form-group">
<label>账号</label>
<input type="text" name="username" required placeholder="请输入账号">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" required placeholder="请输入密码">
</div>
<button type="submit">登录</button>
</form>
<div class="login-wrap">
<div class="theme-row">
<button type="button" id="theme-toggle" class="theme-toggle" aria-label="切换主题">
<span class="icon-light">浅色</span>
<span class="icon-dark">深色</span>
</button>
</div>
<div class="login-box">
<h2>期货监控系统</h2>
{% with messages = get_flashed_messages() %}
{% if messages %}<div class="flash">{{ messages[0] }}</div>{% endif %}
{% endwith %}
<form method="POST">
<div class="form-group">
<label>账号</label>
<input type="text" name="username" required placeholder="请输入账号">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" required placeholder="请输入密码">
</div>
<button type="submit">登录</button>
</form>
</div>
</div>
</body>
</html>
+6 -5
View File
@@ -3,7 +3,8 @@
{% block content %}
<div class="split-grid">
<div class="card">
<h2>今日计划 <span style="font-size:.8rem;color:#888;font-weight:normal">今日 {{ today }}</span></h2>
<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>
<div class="card-body">
<p class="hint" style="margin-bottom:.75rem">开盘前制定,当日有效;下方为进行中计划。</p>
<form action="{{ url_for('add_plan') }}" method="post" class="form-compact">
@@ -33,7 +34,7 @@
<button type="submit" class="btn-primary">添加</button>
</div>
</form>
<h3 style="font-size:.9rem;color:#a9a9ff;margin:.75rem 0 .5rem">进行中</h3>
<h3 class="section-label">进行中</h3>
<div class="list card-scroll">
{% for p in plans %}
<div class="list-item" style="padding:.75rem;font-size:.85rem">
@@ -47,7 +48,7 @@
<a href="{{ url_for('del_plan', pid=p.id) }}" class="btn-del" onclick="return confirm('删除?')"></a>
</div>
{% else %}
<div style="color:#888;padding:.75rem;font-size:.85rem">今日暂无进行中的计划</div>
<div class="empty-hint">今日暂无进行中的计划</div>
{% endfor %}
</div>
</div>
@@ -60,7 +61,7 @@
<div class="field"><label>开始</label><input type="date" name="start" value="{{ start }}"></div>
<div class="field"><label>结束</label><input type="date" name="end" value="{{ end }}"></div>
<button type="submit" class="btn-primary">筛选</button>
<a href="{{ url_for('plans') }}" style="color:#888;font-size:.85rem;padding:.7rem">重置</a>
<a href="{{ url_for('plans') }}" class="text-muted" style="font-size:.85rem;padding:.7rem">重置</a>
</form>
<div class="card-scroll">
<table>
@@ -79,7 +80,7 @@
</td>
</tr>
{% else %}
<tr><td colspan="5" style="color:#888">暂无历史</td></tr>
<tr><td colspan="5" class="text-muted">暂无历史</td></tr>
{% endfor %}
</tbody>
</table>
+1 -1
View File
@@ -126,7 +126,7 @@
<td><a href="{{ url_for('del_review', rid=r.id) }}" class="btn-del" onclick="return confirm('删除?')"></a></td>
</tr>
{% else %}
<tr><td colspan="7" style="color:#888">暂无复盘记录</td></tr>
<tr><td colspan="7" class="text-muted">暂无复盘记录</td></tr>
{% endfor %}
</tbody>
</table>
+9 -9
View File
@@ -4,11 +4,11 @@
<div class="card">
<h2>行情说明</h2>
<p style="font-size:.9rem;color:#ccc;line-height:1.6">
当前行情源:<strong style="color:#4cc2ff">{{ quote_label }}</strong><br>
<p class="hint" style="font-size:.9rem;line-height:1.6">
当前行情源:<strong class="text-accent">{{ quote_label }}</strong><br>
合约代码按<strong>同花顺格式</strong>显示(如 ag2608、IF2606),便于与看盘软件对照;
实际价格通过<strong>新浪财经</strong>免费接口获取,普通用户无需申请 token。<br>
<span style="color:#888;font-size:.85rem">同花顺 iFinD 接口面向机构用户,个人期货通用户一般无法获取 refresh_token,故系统默认不使用。</span>
实际价格通过行情接口获取,普通用户无需申请 token。<br>
<span class="text-muted" style="font-size:.85rem">同花顺 iFinD 接口面向机构用户,个人期货通用户一般无法获取 refresh_token,故系统默认不使用。</span>
</p>
</div>
@@ -19,7 +19,7 @@
<input name="wechat_webhook" type="url" placeholder="企业微信 Webhook 地址" value="{{ webhook }}" style="flex:1;min-width:300px">
<button type="submit" class="btn-primary">保存</button>
</form>
<p style="font-size:.8rem;color:#888;margin-top:.75rem">在企业微信群中添加机器人后,将 Webhook 地址粘贴到上方保存即可。</p>
<p class="hint" style="margin-top:.75rem">在企业微信群中添加机器人后,将 Webhook 地址粘贴到上方保存即可。</p>
</div>
<div class="card">
@@ -27,19 +27,19 @@
<form action="{{ url_for('settings') }}" method="post" style="max-width:400px">
<input type="hidden" name="action" value="password">
<div style="margin-bottom:.75rem">
<label style="font-size:.85rem;color:#a9a9ff;display:block;margin-bottom:.35rem">当前账号</label>
<label class="text-label" style="font-size:.85rem;display:block;margin-bottom:.35rem">当前账号</label>
<input type="text" value="{{ username }}" disabled style="width:100%">
</div>
<div style="margin-bottom:.75rem">
<label style="font-size:.85rem;color:#a9a9ff;display:block;margin-bottom:.35rem">原密码</label>
<label class="text-label" style="font-size:.85rem;display:block;margin-bottom:.35rem">原密码</label>
<input name="old_password" type="password" required style="width:100%">
</div>
<div style="margin-bottom:.75rem">
<label style="font-size:.85rem;color:#a9a9ff;display:block;margin-bottom:.35rem">新密码(至少 6 位)</label>
<label class="text-label" style="font-size:.85rem;display:block;margin-bottom:.35rem">新密码(至少 6 位)</label>
<input name="new_password" type="password" required minlength="6" style="width:100%">
</div>
<div style="margin-bottom:.75rem">
<label style="font-size:.85rem;color:#a9a9ff;display:block;margin-bottom:.35rem">确认新密码</label>
<label class="text-label" style="font-size:.85rem;display:block;margin-bottom:.35rem">确认新密码</label>
<input name="new_password2" type="password" required minlength="6" style="width:100%">
</div>
<button type="submit" class="btn-primary">修改密码</button>
+6 -6
View File
@@ -4,8 +4,8 @@
<div class="stat-grid">
<div class="stat-item"><div class="label">总交易</div><div class="value">{{ total }}</div></div>
<div class="stat-item"><div class="label">止盈</div><div class="value" style="color:#4cd97f">{{ win }}</div></div>
<div class="stat-item"><div class="label">止损</div><div class="value" style="color:#ff6666">{{ loss }}</div></div>
<div class="stat-item"><div class="label">止盈</div><div class="value text-profit">{{ win }}</div></div>
<div class="stat-item"><div class="label">止损</div><div class="value text-loss">{{ loss }}</div></div>
<div class="stat-item"><div class="label">胜率</div><div class="value">{{ rate }}%</div></div>
</div>
@@ -22,7 +22,7 @@
<td>{{ round(s.wins / s.cnt * 100, 2) if s.cnt else 0 }}%</td>
</tr>
{% else %}
<tr><td colspan="4" style="color:#888">暂无数据</td></tr>
<tr><td colspan="4" class="text-muted">暂无数据</td></tr>
{% endfor %}
</tbody>
</table>
@@ -41,7 +41,7 @@
<td>{{ round(t.wins / t.cnt * 100, 2) if t.cnt else 0 }}%</td>
</tr>
{% else %}
<tr><td colspan="4" style="color:#888">暂无数据</td></tr>
<tr><td colspan="4" class="text-muted">暂无数据</td></tr>
{% endfor %}
</tbody>
</table>
@@ -60,7 +60,7 @@
<td>{{ round(d.wins / d.cnt * 100, 2) if d.cnt else 0 }}%</td>
</tr>
{% else %}
<tr><td colspan="4" style="color:#888">暂无数据</td></tr>
<tr><td colspan="4" class="text-muted">暂无数据</td></tr>
{% endfor %}
</tbody>
</table>
@@ -82,7 +82,7 @@
<td>{{ r.created_at[:16] if r.created_at else '' }}</td>
</tr>
{% else %}
<tr><td colspan="4" style="color:#888">暂无数据</td></tr>
<tr><td colspan="4" class="text-muted">暂无数据</td></tr>
{% endfor %}
</tbody>
</table>