Add word-book practice, iOS app shell, and fix embedded WebView blank screen.

Ship dual-track learning (daily accumulation vs textbook),沪教/商务词书 APIs and UI, native iOS wrapper with bundled H5, and production book import on deploy.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-06 21:09:27 +08:00
parent 2fae90b597
commit e76fa586f1
76 changed files with 47488 additions and 445 deletions
+69
View File
@@ -47,6 +47,7 @@ class TranslateResponse(BaseModel):
phonetic: Optional[str] = None
example_en: Optional[str] = None
example_cn: Optional[str] = None
found: bool = True
# Words
@@ -67,6 +68,8 @@ class WordUpdate(BaseModel):
class WordOut(BaseModel):
id: int
user_id: int
book_id: int = 0
book_entry_id: Optional[int] = None
source_text: str
target_text: str
source_lang: str
@@ -195,6 +198,8 @@ class QuizQuestion(BaseModel):
class DailyQuizResponse(BaseModel):
questions: list[QuizQuestion]
total: int
track: str = "accumulation"
book_id: Optional[int] = None
class QuizAnswerRequest(BaseModel):
@@ -223,6 +228,70 @@ class QuizStatsResponse(BaseModel):
daily_target: int
today_completed: int
streak_days: int
track: str = "accumulation"
book_id: Optional[int] = None
# Word books
class WordBookOut(BaseModel):
id: int
slug: str
title: str
description: Optional[str] = None
level: str
word_count: int
unit_count: int
sort_order: int
daily_target: int
master_required_count: int
weak_wrong_threshold: int
learn_mode: str
class Config:
from_attributes = True
class WordBookUnitOut(BaseModel):
unit: int
title: Optional[str] = None
word_count: int
class WordBookDetailOut(WordBookOut):
units: list[WordBookUnitOut] = []
class WordBookProgressOut(BaseModel):
book_id: int
total: int
introduced: int
mastered: int
learning: int
locked: int
class BookPracticeSettingsOut(BaseModel):
book_id: int
daily_target: int
master_required_count: int
weak_wrong_threshold: int
class ActiveBookOut(BaseModel):
book: Optional[WordBookOut] = None
progress: Optional[WordBookProgressOut] = None
settings: Optional[BookPracticeSettingsOut] = None
class SetActiveBookRequest(BaseModel):
book_id: int = Field(ge=1)
class BookPracticeSettingsUpdate(BaseModel):
book_id: Optional[int] = Field(None, ge=1)
daily_target: Optional[int] = Field(None, ge=5, le=50)
master_required_count: Optional[int] = Field(None, ge=1, le=10)
weak_wrong_threshold: Optional[int] = Field(None, ge=1, le=10)
# Settings