refactor: split app structure

This commit is contained in:
Codex
2026-06-15 12:24:49 +08:00
parent df076f6951
commit 5112f7ab4e
17 changed files with 1263 additions and 1090 deletions
+72
View File
@@ -0,0 +1,72 @@
from __future__ import annotations
import json
from pathlib import Path
from fastapi import HTTPException, Request
from pydantic import ValidationError
from .config import ACCOUNTS_PATH, CLASSNOTES_PATH
from .data import Account, Payment, read_accounts, read_classnotes
from .schemas import AccountPayload, RegisterLinesPayload
async def read_register_payload(request: Request) -> RegisterLinesPayload:
body = await request.body()
if not body.strip():
return RegisterLinesPayload()
content_type = request.headers.get("content-type", "").lower()
if "application/json" in content_type:
try:
data = json.loads(body)
if isinstance(data, str):
return RegisterLinesPayload(line=data)
if isinstance(data, list):
return RegisterLinesPayload(lines=data)
if isinstance(data, dict):
return RegisterLinesPayload(**data)
except (json.JSONDecodeError, ValidationError) as exc:
raise ValueError("登记 JSON 格式错误") from exc
raise ValueError("登记 JSON 必须是字符串、字符串数组,或包含 line/lines 的对象")
try:
text = body.decode("utf-8")
except UnicodeDecodeError as exc:
raise ValueError("登记内容必须使用 UTF-8 编码") from exc
return RegisterLinesPayload(lines=text.splitlines())
def load_records():
if not CLASSNOTES_PATH.exists():
raise HTTPException(status_code=503, detail=f"课程记录文件不存在: {CLASSNOTES_PATH}")
return read_classnotes(CLASSNOTES_PATH)
def load_accounts():
if not ACCOUNTS_PATH.exists():
raise HTTPException(status_code=503, detail=f"课时账户文件不存在: {ACCOUNTS_PATH}")
return read_accounts(ACCOUNTS_PATH)
def file_meta(path: Path) -> dict:
if not path.exists():
return {"exists": False, "path": str(path)}
stat = path.stat()
return {
"exists": True,
"path": str(path),
"size": stat.st_size,
"mtime": stat.st_mtime,
}
def payload_to_account(payload: AccountPayload, student_id: str | None = None) -> Account:
return Account(
student_id=student_id if student_id is not None else payload.student_id,
student=payload.student,
payments=[Payment(date=item.date, hours=item.hours) for item in payload.payments],
remaining=payload.remaining,
account_status=payload.account_status,
note=payload.note,
)