feat: 配方显示容量和可做次数;套装成本不超过单买价(配件视为赠品)
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 13s
Test / e2e-test (push) Has been cancelled
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 5s
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Successful in 5s
PR Preview / deploy-preview (pull_request) Successful in 13s
Test / e2e-test (push) Has been cancelled
- 每个配方名后显示容量(单次/5ml/10ml等) - 新增可做次数列(按最先用完的精油计算) - 套装成本分摊使用 min(套装价, 油瓶总价),避免含配件的套装算出比单买贵 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -35,12 +35,14 @@ export function useKitCost() {
|
|||||||
}
|
}
|
||||||
if (totalBottlePrice === 0) return {}
|
if (totalBottlePrice === 0) return {}
|
||||||
|
|
||||||
// Proportional allocation
|
// Proportional allocation — kit accessories treated as freebies,
|
||||||
|
// so oil cost = min(kit price, sum of bottle prices)
|
||||||
|
const effectivePrice = Math.min(kit.price, totalBottlePrice)
|
||||||
const perDrop = {}
|
const perDrop = {}
|
||||||
for (const name of resolved) {
|
for (const name of resolved) {
|
||||||
const meta = oils.oilsMeta[name]
|
const meta = oils.oilsMeta[name]
|
||||||
const bp = oilBottlePrices[name]
|
const bp = oilBottlePrices[name]
|
||||||
const kitCostForOil = (bp / totalBottlePrice) * kit.price
|
const kitCostForOil = (bp / totalBottlePrice) * effectivePrice
|
||||||
const drops = meta ? meta.dropCount : 1
|
const drops = meta ? meta.dropCount : 1
|
||||||
perDrop[name] = drops > 0 ? kitCostForOil / drops : 0
|
perDrop[name] = drops > 0 ? kitCostForOil / drops : 0
|
||||||
}
|
}
|
||||||
@@ -124,6 +126,7 @@ export function useKitCost() {
|
|||||||
id,
|
id,
|
||||||
name: recipe.name,
|
name: recipe.name,
|
||||||
tags: recipe.tags,
|
tags: recipe.tags,
|
||||||
|
volume: recipe.volume,
|
||||||
ingredients: recipe.ingredients,
|
ingredients: recipe.ingredients,
|
||||||
originalCost: recipe.originalCost,
|
originalCost: recipe.originalCost,
|
||||||
costs,
|
costs,
|
||||||
|
|||||||
@@ -39,6 +39,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="th-name">配方名</th>
|
<th class="th-name">配方名</th>
|
||||||
|
<th class="th-times">可做次数</th>
|
||||||
<th class="th-cost">套装成本</th>
|
<th class="th-cost">套装成本</th>
|
||||||
<th class="th-cost">原价成本</th>
|
<th class="th-cost">原价成本</th>
|
||||||
<th class="th-price">售价</th>
|
<th class="th-price">售价</th>
|
||||||
@@ -47,7 +48,8 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="r in activeKitData.recipes" :key="r._id">
|
<tr v-for="r in activeKitData.recipes" :key="r._id">
|
||||||
<td class="td-name">{{ r.name }}</td>
|
<td class="td-name">{{ r.name }} <span class="td-volume">{{ r.volume || '单次' }}</span></td>
|
||||||
|
<td class="td-times">{{ calcMaxTimes(r) }}</td>
|
||||||
<td class="td-cost">{{ fmtPrice(r.kitCost) }}</td>
|
<td class="td-cost">{{ fmtPrice(r.kitCost) }}</td>
|
||||||
<td class="td-cost original">{{ fmtPrice(r.originalCost) }}</td>
|
<td class="td-cost original">{{ fmtPrice(r.originalCost) }}</td>
|
||||||
<td class="td-price">
|
<td class="td-price">
|
||||||
@@ -83,7 +85,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="row in crossComparison" :key="row.id">
|
<tr v-for="row in crossComparison" :key="row.id">
|
||||||
<td class="td-name">{{ row.name }}</td>
|
<td class="td-name">{{ row.name }} <span class="td-volume">{{ row.volume || '单次' }}</span></td>
|
||||||
<td v-for="ka in kitAnalysis" :key="ka.id" :class="row.costs[ka.id] != null ? 'td-kit-available' : 'td-kit-na'">
|
<td v-for="ka in kitAnalysis" :key="ka.id" :class="row.costs[ka.id] != null ? 'td-kit-available' : 'td-kit-na'">
|
||||||
<template v-if="row.costs[ka.id] != null">{{ fmtPrice(row.costs[ka.id]) }}</template>
|
<template v-if="row.costs[ka.id] != null">{{ fmtPrice(row.costs[ka.id]) }}</template>
|
||||||
<template v-else><span class="na">—</span></template>
|
<template v-else><span class="na">—</span></template>
|
||||||
@@ -142,6 +144,20 @@ function saveSellingPrices() {
|
|||||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(sellingPrices.value))
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(sellingPrices.value))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate how many times a recipe can be made with the kit (limited by the oil that runs out first)
|
||||||
|
function calcMaxTimes(recipe) {
|
||||||
|
const ings = (recipe.ingredients || []).filter(i => i.oil && i.oil !== '椰子油' && i.drops > 0)
|
||||||
|
if (!ings.length) return '—'
|
||||||
|
let minTimes = Infinity
|
||||||
|
for (const ing of ings) {
|
||||||
|
const meta = oils.oilsMeta[ing.oil]
|
||||||
|
if (!meta || !meta.dropCount) return '—'
|
||||||
|
const times = Math.floor(meta.dropCount / ing.drops)
|
||||||
|
if (times < minTimes) minTimes = times
|
||||||
|
}
|
||||||
|
return minTimes === Infinity ? '—' : minTimes + '次'
|
||||||
|
}
|
||||||
|
|
||||||
function getSellingPrice(recipeId) {
|
function getSellingPrice(recipeId) {
|
||||||
return sellingPrices.value[recipeId] ?? 0
|
return sellingPrices.value[recipeId] ?? 0
|
||||||
}
|
}
|
||||||
@@ -394,6 +410,8 @@ async function exportExcel(mode) {
|
|||||||
.td-cost.original { color: #999; font-weight: 400; }
|
.td-cost.original { color: #999; font-weight: 400; }
|
||||||
.td-profit { font-weight: 600; color: #4a9d7e; }
|
.td-profit { font-weight: 600; color: #4a9d7e; }
|
||||||
.td-profit.negative { color: #ef5350; }
|
.td-profit.negative { color: #ef5350; }
|
||||||
|
.td-volume { font-size: 10px; color: #b0aab5; margin-left: 4px; }
|
||||||
|
.td-times { color: #6b6375; font-size: 12px; }
|
||||||
.td-kit-available { font-weight: 500; color: #4a9d7e; background: #f0faf5; }
|
.td-kit-available { font-weight: 500; color: #4a9d7e; background: #f0faf5; }
|
||||||
.td-kit-na { background: #fafafa; }
|
.td-kit-na { background: #fafafa; }
|
||||||
.na { color: #ddd; }
|
.na { color: #ddd; }
|
||||||
|
|||||||
Reference in New Issue
Block a user