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
+34
View File
@@ -32,6 +32,40 @@ def run_migrations() -> None:
)
)
if insp.has_table("user_settings"):
cols = {c["name"] for c in insp.get_columns("user_settings")}
if "active_book_id" not in cols:
conn.execute(text("ALTER TABLE user_settings ADD COLUMN active_book_id INTEGER"))
if not insp.has_table("user_book_settings"):
conn.execute(
text(
"""
CREATE TABLE user_book_settings (
id INTEGER PRIMARY KEY AUTO_INCREMENT,
user_id INTEGER NOT NULL,
book_id INTEGER NOT NULL,
daily_target INTEGER NOT NULL DEFAULT 12,
master_required_count INTEGER NOT NULL DEFAULT 3,
weak_wrong_threshold INTEGER NOT NULL DEFAULT 2,
CONSTRAINT uq_user_book_settings UNIQUE (user_id, book_id),
FOREIGN KEY(user_id) REFERENCES users (id),
FOREIGN KEY(book_id) REFERENCES word_books (id)
)
"""
)
)
if insp.has_table("words"):
cols = {c["name"] for c in insp.get_columns("words")}
if "book_id" not in cols:
conn.execute(
text("ALTER TABLE words ADD COLUMN book_id INTEGER NOT NULL DEFAULT 0")
)
conn.execute(text("CREATE INDEX ix_words_book_id ON words (book_id)"))
if "book_entry_id" not in cols:
conn.execute(text("ALTER TABLE words ADD COLUMN book_entry_id INTEGER"))
if insp.has_table("words") and insp.has_table("quiz_records"):
conn.execute(
text(