diff --git a/backend/database.py b/backend/database.py index b62f382..56bf3bc 100644 --- a/backend/database.py +++ b/backend/database.py @@ -221,6 +221,8 @@ def init_db(): c.execute("ALTER TABLE oils ADD COLUMN retail_price REAL") if "is_active" not in oil_cols: c.execute("ALTER TABLE oils ADD COLUMN is_active INTEGER DEFAULT 1") + if "en_name" not in oil_cols: + c.execute("ALTER TABLE oils ADD COLUMN en_name TEXT DEFAULT ''") # Migration: add new columns to category_modules if missing cat_cols = [row[1] for row in c.execute("PRAGMA table_info(category_modules)").fetchall()] diff --git a/backend/main.py b/backend/main.py index 0931c4c..9786964 100644 --- a/backend/main.py +++ b/backend/main.py @@ -79,6 +79,7 @@ class OilIn(BaseModel): bottle_price: float drop_count: int retail_price: Optional[float] = None + en_name: Optional[str] = None class IngredientIn(BaseModel): @@ -649,7 +650,7 @@ def impersonate(body: dict, user=Depends(require_role("admin"))): @app.get("/api/oils") def list_oils(): conn = get_db() - rows = conn.execute("SELECT name, bottle_price, drop_count, retail_price, is_active FROM oils ORDER BY name").fetchall() + rows = conn.execute("SELECT name, bottle_price, drop_count, retail_price, is_active, en_name FROM oils ORDER BY name").fetchall() conn.close() return [dict(r) for r in rows] @@ -658,9 +659,10 @@ def list_oils(): def upsert_oil(oil: OilIn, user=Depends(require_role("admin", "senior_editor"))): conn = get_db() conn.execute( - "INSERT INTO oils (name, bottle_price, drop_count, retail_price) VALUES (?, ?, ?, ?) " - "ON CONFLICT(name) DO UPDATE SET bottle_price=excluded.bottle_price, drop_count=excluded.drop_count, retail_price=excluded.retail_price", - (oil.name, oil.bottle_price, oil.drop_count, oil.retail_price), + "INSERT INTO oils (name, bottle_price, drop_count, retail_price, en_name) VALUES (?, ?, ?, ?, ?) " + "ON CONFLICT(name) DO UPDATE SET bottle_price=excluded.bottle_price, drop_count=excluded.drop_count, " + "retail_price=excluded.retail_price, en_name=COALESCE(excluded.en_name, oils.en_name)", + (oil.name, oil.bottle_price, oil.drop_count, oil.retail_price, oil.en_name), ) log_audit(conn, user["id"], "upsert_oil", "oil", oil.name, oil.name, json.dumps({"bottle_price": oil.bottle_price, "drop_count": oil.drop_count})) diff --git a/frontend/src/App.vue b/frontend/src/App.vue index 77df55b..4e69697 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -15,7 +15,8 @@ @click="toggleUserMenu" > diff --git a/frontend/src/components/LoginModal.vue b/frontend/src/components/LoginModal.vue index 84f7204..9481c4d 100644 --- a/frontend/src/components/LoginModal.vue +++ b/frontend/src/components/LoginModal.vue @@ -104,8 +104,11 @@ async function submit() { ui.showToast('注册成功') } emit('close') - // Reload page data after auth change - window.location.reload() + if (ui.pendingAction) { + ui.runPendingAction() + } else { + window.location.reload() + } } catch (e) { errorMsg.value = e?.message || (mode.value === 'login' ? '登录失败,请检查用户名和密码' : '注册失败,请重试') } finally { @@ -119,7 +122,7 @@ async function submit() { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.35); - z-index: 5000; + z-index: 6000; display: flex; align-items: center; justify-content: center; diff --git a/frontend/src/components/RecipeDetailOverlay.vue b/frontend/src/components/RecipeDetailOverlay.vue index d2a6027..02c8d27 100644 --- a/frontend/src/components/RecipeDetailOverlay.vue +++ b/frontend/src/components/RecipeDetailOverlay.vue @@ -19,7 +19,7 @@ class="action-btn action-btn-sm" @click="viewMode = 'editor'" >编辑 - + @@ -36,21 +36,33 @@ >English + +
+ +
+
- - +
+ +
{{ brand.brand_name }}
+
{{ dilutionDesc }}
-
- {{ cardLang === 'en' ? '📝 ' + recipe.note : '📝 ' + recipe.note }} +
+ {{ '📝 ' + displayRecipe.note }}
@@ -126,6 +138,11 @@ class="action-btn" @click="showTranslationEditor = true" >✏️ 修改翻译 +
@@ -156,7 +173,7 @@
- +
@@ -209,10 +226,29 @@
- +
+ +
+
+ {{ name }} + {{ oilEn(name) }} +
+
+
- +
@@ -342,6 +378,7 @@