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")
|
c.execute("ALTER TABLE oils ADD COLUMN is_active INTEGER DEFAULT 1")
|
||||||
if "en_name" not in oil_cols:
|
if "en_name" not in oil_cols:
|
||||||
c.execute("ALTER TABLE oils ADD COLUMN en_name TEXT DEFAULT ''")
|
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
|
# Migration: add new columns to category_modules if missing
|
||||||
cat_cols = [row[1] for row in c.execute("PRAGMA table_info(category_modules)").fetchall()]
|
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
|
retail_price: Optional[float] = None
|
||||||
en_name: Optional[str] = None
|
en_name: Optional[str] = None
|
||||||
is_active: Optional[int] = None
|
is_active: Optional[int] = None
|
||||||
|
unit: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class IngredientIn(BaseModel):
|
class IngredientIn(BaseModel):
|
||||||
@@ -715,7 +716,7 @@ def impersonate(body: dict, user=Depends(require_role("admin"))):
|
|||||||
@app.get("/api/oils")
|
@app.get("/api/oils")
|
||||||
def list_oils():
|
def list_oils():
|
||||||
conn = get_db()
|
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()
|
conn.close()
|
||||||
return [dict(r) for r in rows]
|
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"))):
|
def upsert_oil(oil: OilIn, user=Depends(require_role("admin", "senior_editor"))):
|
||||||
conn = get_db()
|
conn = get_db()
|
||||||
conn.execute(
|
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, "
|
"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), "
|
"retail_price=excluded.retail_price, en_name=COALESCE(excluded.en_name, oils.en_name), "
|
||||||
"is_active=COALESCE(excluded.is_active, oils.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.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,
|
log_audit(conn, user["id"], "upsert_oil", "oil", oil.name, oil.name,
|
||||||
json.dumps({"bottle_price": oil.bottle_price, "drop_count": oil.drop_count}))
|
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,
|
retailPrice: oil.retail_price ?? null,
|
||||||
isActive: oil.is_active !== 0,
|
isActive: oil.is_active !== 0,
|
||||||
enName: oil.en_name ?? null,
|
enName: oil.en_name ?? null,
|
||||||
|
unit: oil.unit || 'drop',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oils.value = newOils
|
oils.value = newOils
|
||||||
@@ -93,18 +94,22 @@ export const useOilsStore = defineStore('oils', () => {
|
|||||||
delete oilsMeta.value[name]
|
delete oilsMeta.value[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPortionUnit(name) {
|
function isMlUnit(name) {
|
||||||
const meta = oilsMeta.value[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') {
|
function unitLabel(name, lang = 'zh') {
|
||||||
if (isPortionUnit(name)) return lang === 'en' ? 'portion' : '份'
|
if (isMlUnit(name)) return 'ml'
|
||||||
return lang === 'en' ? 'drop' : '滴'
|
return lang === 'en' ? 'drop' : '滴'
|
||||||
}
|
}
|
||||||
|
|
||||||
function unitLabelPlural(name, count, lang = 'zh') {
|
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') : '滴'
|
return lang === 'en' ? (count === 1 ? 'drop' : 'drops') : '滴'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user