From a5383d8ca1cf10282d2a22ae68676358b3ee8e1c Mon Sep 17 00:00:00 2001 From: dekun Date: Tue, 19 May 2026 01:10:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=90=9C=E7=B4=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 9 +- app.py | 30 +++++- index.html | 290 +++++++++++++++++++++++++++++++++-------------------- 3 files changed, 213 insertions(+), 116 deletions(-) diff --git a/README.md b/README.md index 2e2cfba..33a6f9b 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,9 @@ ## 功能 -- 账户数量不限,每项含 `username` / `api_key` / `api_secret` +- 交易所:`binance` / `okx` / `gate`(OKX 额外保存密码 Passphrase) +- 账户数量不限,每项含 `exchange` / `username` / `api_key` / `api_secret` +- 添加后默认不展示列表,需选择交易所点击「确认」查询 - 黑色专业界面,列表展示 + 每项 3 个复制按钮(**复制始终为明文**) - 可选界面打码显示,不影响复制内容 - 数据持久化至 `data.json` @@ -76,9 +78,11 @@ PM2 守护:`./pm2-start.sh`(Linux)或 `.\pm2-start.ps1`(Windows) ```json { "id": "uuid", + "exchange": "binance", "username": "账户名称", "api_key": "API Key", - "api_secret": "API Secret" + "api_secret": "API Secret", + "password": "仅 OKX 需要" } ``` @@ -90,6 +94,7 @@ PM2 守护:`./pm2-start.sh`(Linux)或 `.\pm2-start.ps1`(Windows) |------|------|------| | GET | `/` | 前端页面 | | GET | `/api/accounts` | 获取全部账户 | +| GET | `/api/accounts?exchange=binance` | 按交易所筛选 | | POST | `/api/accounts` | 新增账户 | | DELETE | `/api/accounts/` | 删除账户 | diff --git a/app.py b/app.py index 63df032..1ce609f 100644 --- a/app.py +++ b/app.py @@ -12,6 +12,7 @@ app = Flask(__name__) BASE_DIR = Path(__file__).resolve().parent DATA_FILE = BASE_DIR / "data.json" +VALID_EXCHANGES = frozenset({"binance", "okx", "gate"}) def load_accounts(): @@ -33,16 +34,34 @@ def save_accounts(accounts): def validate_account_payload(payload): + exchange = (payload.get("exchange") or "").strip().lower() username = (payload.get("username") or "").strip() api_key = (payload.get("api_key") or "").strip() api_secret = (payload.get("api_secret") or "").strip() + + if exchange not in VALID_EXCHANGES: + return None, "请选择交易所:binance / okx / gate" if not username: return None, "账户名称不能为空" if not api_key: return None, "API Key 不能为空" if not api_secret: return None, "API Secret 不能为空" - return {"username": username, "api_key": api_key, "api_secret": api_secret}, None + + account = { + "exchange": exchange, + "username": username, + "api_key": api_key, + "api_secret": api_secret, + } + + if exchange == "okx": + password = (payload.get("password") or "").strip() + if not password: + return None, "OKX 密码(Passphrase)不能为空" + account["password"] = password + + return account, None @app.route("/") @@ -52,7 +71,13 @@ def index(): @app.route("/api/accounts", methods=["GET"]) def list_accounts(): - return jsonify(load_accounts()) + accounts = load_accounts() + exchange = (request.args.get("exchange") or "").strip().lower() + if exchange: + if exchange not in VALID_EXCHANGES: + return jsonify({"error": "无效交易所"}), 400 + accounts = [a for a in accounts if a.get("exchange") == exchange] + return jsonify(accounts) @app.route("/api/accounts", methods=["POST"]) @@ -80,5 +105,4 @@ def delete_account(account_id): if __name__ == "__main__": - # 0.0.0.0:本机 + 局域网均可访问(如 http://192.168.1.100:5200) app.run(host="0.0.0.0", port=5200, debug=False) diff --git a/index.html b/index.html index ea53424..f073f34 100644 --- a/index.html +++ b/index.html @@ -43,17 +43,8 @@ border-bottom: 1px solid var(--border); } - header h1 { - font-size: 1.5rem; - font-weight: 600; - letter-spacing: -0.02em; - } - - header p { - margin-top: 6px; - font-size: 0.875rem; - color: var(--text-muted); - } + header h1 { font-size: 1.5rem; font-weight: 600; } + header p { margin-top: 6px; font-size: 0.875rem; color: var(--text-muted); } .panel { background: var(--surface); @@ -72,14 +63,12 @@ margin-bottom: 16px; } - .form-grid { - display: grid; - gap: 12px; - } + .form-grid { display: grid; gap: 12px; } - @media (min-width: 640px) { - .form-grid { grid-template-columns: 1fr 1fr 1fr; } - .form-actions { grid-column: 1 / -1; } + @media (min-width: 720px) { + .form-grid { grid-template-columns: repeat(3, 1fr); } + .form-grid .span-3 { grid-column: span 3; } + .form-grid .span-2 { grid-column: span 2; } } label { @@ -89,55 +78,43 @@ margin-bottom: 4px; } - input { + input, select { width: 100%; padding: 10px 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; color: var(--text); - font-family: var(--mono); font-size: 0.8125rem; } - input:focus { + input { font-family: var(--mono); } + select { font-family: var(--font); cursor: pointer; } + + input:focus, select:focus { outline: none; border-color: var(--accent); } + .hidden { display: none !important; } + .btn { display: inline-flex; align-items: center; justify-content: center; - gap: 6px; padding: 8px 14px; font-size: 0.8125rem; font-weight: 500; border: none; border-radius: 6px; cursor: pointer; - transition: background 0.15s, color 0.15s; font-family: var(--font); + white-space: nowrap; } - .btn-primary { - background: var(--accent); - color: #fff; - } - + .btn-primary { background: var(--accent); color: #fff; } .btn-primary:hover { background: var(--accent-hover); } - .btn-ghost { - background: transparent; - color: var(--text-muted); - border: 1px solid var(--border); - } - - .btn-ghost:hover { - background: var(--surface-hover); - color: var(--text); - } - .btn-copy { background: var(--bg); color: var(--text-muted); @@ -147,40 +124,36 @@ flex-shrink: 0; } - .btn-copy:hover { - color: var(--text); - border-color: var(--accent); - } - - .btn-copy.copied { - color: var(--success); - border-color: var(--success); - } + .btn-copy:hover { color: var(--text); border-color: var(--accent); } + .btn-copy.copied { color: var(--success); border-color: var(--success); } .btn-danger { background: transparent; color: var(--danger); - border: 1px solid transparent; padding: 4px 8px; font-size: 0.75rem; } - .btn-danger:hover { - background: rgba(239, 68, 68, 0.1); - border-color: var(--danger); + .btn-danger:hover { background: rgba(239, 68, 68, 0.1); } + + .search-row { + display: flex; + gap: 10px; + align-items: flex-end; } + .search-row .search-select { flex: 1; } + .toolbar { display: flex; align-items: center; justify-content: space-between; + flex-wrap: wrap; + gap: 12px; margin-bottom: 16px; } - .toolbar .count { - font-size: 0.8125rem; - color: var(--text-muted); - } + .toolbar .count { font-size: 0.8125rem; color: var(--text-muted); } .toggle-mask { display: flex; @@ -189,7 +162,6 @@ font-size: 0.8125rem; color: var(--text-muted); cursor: pointer; - user-select: none; } .toggle-mask input { width: auto; accent-color: var(--accent); } @@ -203,8 +175,6 @@ padding: 16px; } - .account-card:hover { border-color: #3f3f48; } - .account-header { display: flex; align-items: center; @@ -214,11 +184,25 @@ border-bottom: 1px solid var(--border); } - .account-name { - font-weight: 600; - font-size: 0.9375rem; + .account-title { + display: flex; + align-items: center; + gap: 8px; } + .badge { + font-size: 0.6875rem; + font-weight: 600; + text-transform: uppercase; + padding: 2px 8px; + border-radius: 4px; + background: var(--bg); + border: 1px solid var(--border); + color: var(--accent); + } + + .account-name { font-weight: 600; font-size: 0.9375rem; } + .field { display: flex; align-items: center; @@ -229,7 +213,7 @@ .field:last-child { margin-bottom: 0; } .field-label { - width: 88px; + width: 100px; flex-shrink: 0; font-size: 0.75rem; color: var(--text-muted); @@ -241,7 +225,6 @@ font-family: var(--mono); font-size: 0.8125rem; word-break: break-all; - color: var(--text); } .empty { @@ -264,62 +247,85 @@ border-radius: 6px; font-size: 0.8125rem; opacity: 0; - transform: translateY(8px); - transition: opacity 0.2s, transform 0.2s; + transition: opacity 0.2s; pointer-events: none; z-index: 100; } - .toast.show { - opacity: 1; - transform: translateY(0); - } + .toast.show { opacity: 1; } - .error-msg { - color: var(--danger); - font-size: 0.8125rem; - margin-top: 8px; - } + .error-msg { color: var(--danger); font-size: 0.8125rem; margin-top: 8px; }

API 密钥管理

-

本地多账户存储 · 数据保存在 data.json

+

按交易所分类存储 · 查询后显示 · 复制始终为明文

添加账户

+
+ + +
- + +
+
- +
- +
-
+
+
+

查询账户

+
+
+ + +
+ +
+
+
- 共 0 个账户 + 未查询
- +
@@ -327,8 +333,12 @@