feat: 护肤品用ml单位,精油用滴,通过unit字段区分
All checks were successful
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 12s
Test / e2e-test (push) Successful in 53s
All checks were successful
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 6s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 12s
Test / e2e-test (push) Successful in 53s
- 后端: oils表新增unit列(drop/ml),API返回unit字段 - 前端: 根据unit='ml'显示ml单位,精油显示滴/drop - 护肤品drop_count改为实际ml容量,成本按用量比例计算 如玫瑰护手霜100ml ¥135,配方用30ml → 成本¥40.5 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -227,6 +227,8 @@ def init_db():
|
||||
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 ''")
|
||||
if "unit" not in oil_cols:
|
||||
c.execute("ALTER TABLE oils ADD COLUMN unit TEXT DEFAULT 'drop'")
|
||||
|
||||
# Migration: add new columns to category_modules if missing
|
||||
cat_cols = [row[1] for row in c.execute("PRAGMA table_info(category_modules)").fetchall()]
|
||||
|
||||
@@ -87,6 +87,7 @@ class OilIn(BaseModel):
|
||||
retail_price: Optional[float] = None
|
||||
en_name: Optional[str] = None
|
||||
is_active: Optional[int] = None
|
||||
unit: Optional[str] = None
|
||||
|
||||
|
||||
class IngredientIn(BaseModel):
|
||||
@@ -715,7 +716,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, en_name FROM oils ORDER BY name").fetchall()
|
||||
rows = conn.execute("SELECT name, bottle_price, drop_count, retail_price, is_active, en_name, unit FROM oils ORDER BY name").fetchall()
|
||||
conn.close()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
@@ -724,11 +725,11 @@ 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, en_name, is_active) VALUES (?, ?, ?, ?, ?, ?) "
|
||||
"INSERT INTO oils (name, bottle_price, drop_count, retail_price, en_name, is_active, unit) 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), "
|
||||
"is_active=COALESCE(excluded.is_active, oils.is_active)",
|
||||
(oil.name, oil.bottle_price, oil.drop_count, oil.retail_price, title_case(oil.en_name) if oil.en_name else oil.en_name, oil.is_active),
|
||||
"is_active=COALESCE(excluded.is_active, oils.is_active), unit=COALESCE(excluded.unit, oils.unit)",
|
||||
(oil.name, oil.bottle_price, oil.drop_count, oil.retail_price, title_case(oil.en_name) if oil.en_name else oil.en_name, oil.is_active, oil.unit),
|
||||
)
|
||||
log_audit(conn, user["id"], "upsert_oil", "oil", oil.name, oil.name,
|
||||
json.dumps({"bottle_price": oil.bottle_price, "drop_count": oil.drop_count}))
|
||||
|
||||
@@ -70,6 +70,7 @@ export const useOilsStore = defineStore('oils', () => {
|
||||
retailPrice: oil.retail_price ?? null,
|
||||
isActive: oil.is_active !== 0,
|
||||
enName: oil.en_name ?? null,
|
||||
unit: oil.unit || 'drop',
|
||||
}
|
||||
}
|
||||
oils.value = newOils
|
||||
@@ -93,18 +94,22 @@ export const useOilsStore = defineStore('oils', () => {
|
||||
delete oilsMeta.value[name]
|
||||
}
|
||||
|
||||
function isPortionUnit(name) {
|
||||
function isMlUnit(name) {
|
||||
const meta = oilsMeta.value[name]
|
||||
return meta && meta.dropCount === 1
|
||||
return meta && meta.unit === 'ml'
|
||||
}
|
||||
|
||||
function isPortionUnit(name) {
|
||||
return isMlUnit(name)
|
||||
}
|
||||
|
||||
function unitLabel(name, lang = 'zh') {
|
||||
if (isPortionUnit(name)) return lang === 'en' ? 'portion' : '份'
|
||||
if (isMlUnit(name)) return 'ml'
|
||||
return lang === 'en' ? 'drop' : '滴'
|
||||
}
|
||||
|
||||
function unitLabelPlural(name, count, lang = 'zh') {
|
||||
if (isPortionUnit(name)) return lang === 'en' ? (count === 1 ? 'portion' : 'portions') : '份'
|
||||
if (isMlUnit(name)) return 'ml'
|
||||
return lang === 'en' ? (count === 1 ? 'drop' : 'drops') : '滴'
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user