98 lines
2.8 KiB
Python
98 lines
2.8 KiB
Python
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()
|