From dee4b1649a5b47139812f3fd790bf88c405d343f Mon Sep 17 00:00:00 2001 From: YoYo Date: Tue, 7 Apr 2026 22:27:21 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=8D=A1=E7=89=87=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E5=8A=A0=E5=85=A5=E5=AE=B9=E9=87=8F=E5=88=87=E6=8D=A2=EF=BC=8C?= =?UTF-8?q?=E9=9D=9E=E5=8D=95=E6=AC=A1=E6=BB=B4=E6=95=B0=E5=9B=9B=E8=88=8D?= =?UTF-8?q?=E4=BA=94=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - VOLUME_DROPS 新增「单次」(null,不缩放) - 新增 scaleIngredients() 按比例缩放成分 - 卡片预览区加入容量切换按钮,切换后实时更新滴数与成本 - priceInfo 与 coconutDrops 均基于缩放后数据 Co-Authored-By: Claude Sonnet 4.6 --- .../src/components/RecipeDetailOverlay.vue | 50 ++++++++++++++++--- frontend/src/stores/oils.js | 1 + 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/RecipeDetailOverlay.vue b/frontend/src/components/RecipeDetailOverlay.vue index 6d9d651..b9229ef 100644 --- a/frontend/src/components/RecipeDetailOverlay.vue +++ b/frontend/src/components/RecipeDetailOverlay.vue @@ -36,6 +36,17 @@ >English + +
+ +
+
@@ -382,6 +393,7 @@ const viewMode = ref('card') const cardRef = ref(null) const cardImageUrl = ref(null) const cardLang = ref('zh') +const selectedCardVolume = ref('单次') const showTranslationEditor = ref(false) const customRecipeNameEn = ref('') const customOilNameEn = ref({}) @@ -400,14 +412,30 @@ const canEditThisRecipe = computed(() => { const isFav = computed(() => recipesStore.isFavorite(recipe.value)) -// Card ingredients: exclude coconut oil -const cardIngredients = computed(() => - recipe.value.ingredients.filter(ing => ing.oil !== '椰子油') +// Scale ingredients proportionally to target volume; '单次' = no scaling +function scaleIngredients(ingredients, volume) { + const targetDrops = VOLUME_DROPS[volume] + if (!targetDrops) return ingredients // 单次:不缩放 + const totalDrops = ingredients.reduce((sum, ing) => sum + (ing.drops || 0), 0) + if (totalDrops === 0) return ingredients + return ingredients.map(ing => ({ + ...ing, + drops: Math.round(ing.drops * targetDrops / totalDrops), + })) +} + +// Card ingredients: scaled to selected volume, coconut oil excluded from display +const scaledCardIngredients = computed(() => + scaleIngredients(recipe.value.ingredients, selectedCardVolume.value) ) -// Coconut oil drops +const cardIngredients = computed(() => + scaledCardIngredients.value.filter(ing => ing.oil !== '椰子油') +) + +// Coconut oil drops (from scaled set) const coconutDrops = computed(() => { - const coco = recipe.value.ingredients.find(ing => ing.oil === '椰子油') + const coco = scaledCardIngredients.value.find(ing => ing.oil === '椰子油') return coco ? coco.drops : 0 }) @@ -433,7 +461,7 @@ const dilutionDesc = computed(() => { : `该配方适用于单次用量(共${totalDrops}滴),其中纯精油 ${totalEoDrops.value} 滴,椰子油 ${coconutDrops.value} 滴,稀释比例为 1:${ratio}` }) -const priceInfo = computed(() => oilsStore.fmtCostWithRetail(recipe.value.ingredients)) +const priceInfo = computed(() => oilsStore.fmtCostWithRetail(scaledCardIngredients.value)) // Today string const todayStr = computed(() => { @@ -512,6 +540,12 @@ function switchLang(lang) { nextTick(() => generateCardImage()) } +function onCardVolumeChange(ml) { + selectedCardVolume.value = ml + cardImageUrl.value = null + nextTick(() => generateCardImage()) +} + async function saveImage() { if (!cardImageUrl.value) { await generateCardImage() @@ -1469,6 +1503,10 @@ async function saveRecipe() { margin-bottom: 10px; } +.card-volume-controls { + margin: 8px 0 12px; +} + .volume-btn { padding: 7px 16px; border: 1.5px solid var(--border, #e0d4c0); diff --git a/frontend/src/stores/oils.js b/frontend/src/stores/oils.js index 2b2f647..f890b0e 100644 --- a/frontend/src/stores/oils.js +++ b/frontend/src/stores/oils.js @@ -5,6 +5,7 @@ import { api } from '../composables/useApi' export const DROPS_PER_ML = 18.6 export const VOLUME_DROPS = { + '单次': null, '2.5': 46, '5': 93, '10': 186,