fix: 非单次容量时滴数四舍五入为整数

- VOLUME_DROPS 新增「单次」选项(值为 null,不缩放)
- 新增 scaleIngredients(),按目标容量等比缩放滴数,非单次时 Math.round 取整
- 卡片预览新增容量选择器,使用 scaledIngredients 展示缩放后的滴数及成本
- 编辑器成本合计同步反映已选容量的缩放结果

Co-Authored-By: YoYo <yoyo@euphon.net>
This commit is contained in:
2026-04-07 22:04:28 +00:00
parent 7ba1e28370
commit 1ca9943d50
2 changed files with 30 additions and 5 deletions

View File

@@ -18,6 +18,15 @@
<!-- Card View -->
<div v-if="viewMode === 'card'" class="detail-card-view">
<div class="volume-controls" style="margin-bottom:12px">
<button
v-for="(drops, ml) in volumeOptions"
:key="ml"
class="volume-btn"
:class="{ active: selectedVolume === ml }"
@click="selectedVolume = ml"
>{{ ml === '单次' ? '单次' : ml + 'ml' }}</button>
</div>
<div ref="cardRef" class="export-card">
<div class="export-card-name">{{ recipe.name }}</div>
<div v-if="recipe.tags && recipe.tags.length" class="export-card-tags">
@@ -32,7 +41,7 @@
</tr>
</thead>
<tbody>
<tr v-for="(ing, i) in recipe.ingredients" :key="i">
<tr v-for="(ing, i) in scaledIngredients" :key="i">
<td>{{ ing.oil }}</td>
<td>{{ ing.drops }}</td>
<td>{{ oilsStore.fmtPrice(oilsStore.pricePerDrop(ing.oil) * ing.drops) }}</td>
@@ -124,7 +133,7 @@
class="volume-btn"
:class="{ active: selectedVolume === ml }"
@click="selectedVolume = ml"
>{{ ml }}ml</button>
>{{ ml === '单次' ? '单次' : ml + 'ml' }}</button>
</div>
</div>
@@ -175,13 +184,26 @@ const ui = useUiStore()
const viewMode = ref('card')
const cardRef = ref(null)
const showTagPicker = ref(false)
const selectedVolume = ref('5')
const selectedVolume = ref('单次')
const volumeOptions = VOLUME_DROPS
// Source recipe
const recipe = computed(() => recipesStore.recipes[props.recipeIndex] || { name: '', ingredients: [], tags: [], note: '' })
const priceInfo = computed(() => oilsStore.fmtCostWithRetail(recipe.value.ingredients))
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),
}))
}
const scaledIngredients = computed(() => scaleIngredients(recipe.value.ingredients, selectedVolume.value))
const priceInfo = computed(() => oilsStore.fmtCostWithRetail(scaledIngredients.value))
// Editable copies
const editName = ref('')
@@ -189,7 +211,9 @@ const editNote = ref('')
const editTags = ref([])
const editIngredients = ref([])
const editPriceInfo = computed(() => oilsStore.fmtCostWithRetail(editIngredients.value.filter(i => i.oil)))
const editPriceInfo = computed(() =>
oilsStore.fmtCostWithRetail(scaleIngredients(editIngredients.value.filter(i => i.oil), selectedVolume.value))
)
onMounted(() => {
const r = recipe.value

View File

@@ -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,