feat: 新增打字练习记录与首页记录列表
This commit is contained in:
@@ -12,6 +12,7 @@ from server.db import BASE_DIR, get_db, init_db
|
||||
from server.entries_api import entries_bp
|
||||
from server.settings_api import settings_bp
|
||||
from server.tts_api import tts_bp
|
||||
from server.typing_api import typing_bp
|
||||
from server.vocab_api import vocab_bp
|
||||
|
||||
|
||||
@@ -30,6 +31,7 @@ def create_app():
|
||||
app.register_blueprint(vocab_bp)
|
||||
app.register_blueprint(settings_bp)
|
||||
app.register_blueprint(tts_bp)
|
||||
app.register_blueprint(typing_bp)
|
||||
|
||||
@app.post("/api/register")
|
||||
def register():
|
||||
|
||||
@@ -51,6 +51,23 @@ CREATE TABLE IF NOT EXISTS settings (
|
||||
extra_config TEXT NOT NULL DEFAULT '{}',
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS typing_logs (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
mode TEXT NOT NULL,
|
||||
category_id TEXT NOT NULL DEFAULT '',
|
||||
category_name TEXT NOT NULL DEFAULT '',
|
||||
item_count INTEGER NOT NULL DEFAULT 0,
|
||||
correct_keys INTEGER NOT NULL DEFAULT 0,
|
||||
error_keys INTEGER NOT NULL DEFAULT 0,
|
||||
accuracy INTEGER NOT NULL DEFAULT 0,
|
||||
duration_seconds INTEGER NOT NULL DEFAULT 0,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_typing_logs_user_created
|
||||
ON typing_logs(user_id, created_at);
|
||||
"""
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
from flask import Blueprint, jsonify, request
|
||||
|
||||
from server.auth import login_required
|
||||
from server.db import get_db, now_iso
|
||||
|
||||
typing_bp = Blueprint("typing", __name__)
|
||||
|
||||
|
||||
def row_to_dict(row):
|
||||
return dict(row)
|
||||
|
||||
|
||||
def to_int(value, default=0):
|
||||
try:
|
||||
return int(value)
|
||||
except (TypeError, ValueError):
|
||||
return default
|
||||
|
||||
|
||||
@typing_bp.get("/api/typing/logs")
|
||||
@login_required
|
||||
def list_typing_logs(user):
|
||||
conn = get_db()
|
||||
try:
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT id, mode, category_id, category_name, item_count,
|
||||
correct_keys, error_keys, accuracy, duration_seconds, created_at
|
||||
FROM typing_logs
|
||||
WHERE user_id = ?
|
||||
ORDER BY id DESC
|
||||
LIMIT 200
|
||||
""",
|
||||
(user["id"],),
|
||||
).fetchall()
|
||||
return jsonify([row_to_dict(r) for r in rows])
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
|
||||
@typing_bp.post("/api/typing/logs")
|
||||
@login_required
|
||||
def create_typing_log(user):
|
||||
data = request.get_json(silent=True) or {}
|
||||
mode = (data.get("mode") or "").strip()
|
||||
if mode not in ("vocab", "phrases"):
|
||||
return jsonify({"error": "练习类型不正确"}), 400
|
||||
|
||||
item_count = to_int(data.get("itemCount"))
|
||||
correct_keys = to_int(data.get("correctKeys"))
|
||||
error_keys = to_int(data.get("errorKeys"))
|
||||
accuracy = to_int(data.get("accuracy"))
|
||||
duration_seconds = to_int(data.get("durationSeconds"))
|
||||
|
||||
if item_count < 1:
|
||||
return jsonify({"error": "练习数量不正确"}), 400
|
||||
if accuracy < 0 or accuracy > 100:
|
||||
return jsonify({"error": "正确率不正确"}), 400
|
||||
if duration_seconds < 0:
|
||||
return jsonify({"error": "练习时长不正确"}), 400
|
||||
|
||||
conn = get_db()
|
||||
try:
|
||||
cur = conn.execute(
|
||||
"""
|
||||
INSERT INTO typing_logs (
|
||||
user_id, mode, category_id, category_name, item_count,
|
||||
correct_keys, error_keys, accuracy, duration_seconds, created_at
|
||||
)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
user["id"],
|
||||
mode,
|
||||
(data.get("categoryId") or "").strip(),
|
||||
(data.get("categoryName") or "").strip(),
|
||||
item_count,
|
||||
max(0, correct_keys),
|
||||
max(0, error_keys),
|
||||
accuracy,
|
||||
duration_seconds,
|
||||
now_iso(),
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
row = conn.execute(
|
||||
"""
|
||||
SELECT id, mode, category_id, category_name, item_count,
|
||||
correct_keys, error_keys, accuracy, duration_seconds, created_at
|
||||
FROM typing_logs
|
||||
WHERE id = ?
|
||||
""",
|
||||
(cur.lastrowid,),
|
||||
).fetchone()
|
||||
return jsonify(row_to_dict(row)), 201
|
||||
finally:
|
||||
conn.close()
|
||||
Reference in New Issue
Block a user