feat: 新增产品表单(ml/g/颗)+配方卡片显示产品容量
All checks were successful
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) Successful in 50s
All checks were successful
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) Successful in 50s
- 精油价目新增分两个tab:新增精油(标准容量) / 新增其他产品(ml/g/颗) - saveOil支持unit参数 - 配方卡片:含产品的配方直接显示产品用量+单位(如30g) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,13 +56,10 @@ const volumeLabel = computed(() => {
|
||||
if (ml <= 2) return '单次'
|
||||
return `${Math.round(ml)}ml`
|
||||
}
|
||||
// Non-coconut: check if has portion product, extract volume from note
|
||||
const hasPortion = ings.some(i => oilsStore.isPortionUnit(i.oil))
|
||||
if (hasPortion) {
|
||||
const note = props.recipe.note || ''
|
||||
const m = note.match(/(\d+)\s*(ml|毫升|克|g)/i)
|
||||
if (m) return `${m[1]}${m[2].toLowerCase()}`
|
||||
return '调配'
|
||||
// Non-coconut: find portion product and show its amount + unit
|
||||
const portionIng = ings.find(i => oilsStore.isPortionUnit(i.oil))
|
||||
if (portionIng) {
|
||||
return `${portionIng.drops}${oilsStore.unitLabel(portionIng.oil)}`
|
||||
}
|
||||
return ''
|
||||
})
|
||||
|
||||
@@ -77,14 +77,16 @@ export const useOilsStore = defineStore('oils', () => {
|
||||
oilsMeta.value = newMeta
|
||||
}
|
||||
|
||||
async function saveOil(name, bottlePrice, dropCount, retailPrice, enName = null) {
|
||||
await api.post('/api/oils', {
|
||||
async function saveOil(name, bottlePrice, dropCount, retailPrice, enName = null, unit = null) {
|
||||
const payload = {
|
||||
name,
|
||||
bottle_price: bottlePrice,
|
||||
drop_count: dropCount,
|
||||
retail_price: retailPrice,
|
||||
en_name: enName,
|
||||
})
|
||||
}
|
||||
if (unit) payload.unit = unit
|
||||
await api.post('/api/oils', payload)
|
||||
await loadOils()
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,12 @@
|
||||
|
||||
<!-- Add Oil Form (toggleable) -->
|
||||
<div v-if="showAddForm && auth.canManage" class="add-oil-form">
|
||||
<div class="form-row">
|
||||
<div class="add-type-tabs">
|
||||
<button class="add-type-tab" :class="{ active: addType === 'oil' }" @click="addType = 'oil'">新增精油</button>
|
||||
<button class="add-type-tab" :class="{ active: addType === 'product' }" @click="addType = 'product'">新增其他产品</button>
|
||||
</div>
|
||||
<!-- 新增精油 -->
|
||||
<div v-if="addType === 'oil'" class="form-row">
|
||||
<input v-model="newOilName" style="flex:1;min-width:120px" placeholder="精油名称" class="form-input-sm" />
|
||||
<input v-model="newOilEnName" style="flex:1;min-width:100px" placeholder="英文名" class="form-input-sm" />
|
||||
<input v-model.number="newBottlePrice" style="width:100px" type="number" step="0.01" min="0" placeholder="会员价 ¥" class="form-input-sm" />
|
||||
@@ -124,6 +129,20 @@
|
||||
<input v-model.number="newRetailPrice" style="width:100px" type="number" step="0.01" min="0" placeholder="零售价 ¥" class="form-input-sm" />
|
||||
<button class="btn btn-primary btn-sm" @click="addOil" :disabled="!newOilName.trim()">➕ 添加</button>
|
||||
</div>
|
||||
<!-- 新增其他产品 -->
|
||||
<div v-else class="form-row">
|
||||
<input v-model="newOilName" style="flex:1;min-width:120px" placeholder="产品名称" class="form-input-sm" />
|
||||
<input v-model="newOilEnName" style="flex:1;min-width:100px" placeholder="英文名" class="form-input-sm" />
|
||||
<input v-model.number="newBottlePrice" style="width:100px" type="number" step="0.01" min="0" placeholder="会员价 ¥" class="form-input-sm" />
|
||||
<input v-model.number="newProductAmount" style="width:70px" type="number" step="1" min="1" placeholder="容量" class="form-input-sm" />
|
||||
<select v-model="newProductUnit" class="form-input-sm" style="width:60px">
|
||||
<option value="ml">ml</option>
|
||||
<option value="g">g</option>
|
||||
<option value="capsule">颗</option>
|
||||
</select>
|
||||
<input v-model.number="newRetailPrice" style="width:100px" type="number" step="0.01" min="0" placeholder="零售价 ¥" class="form-input-sm" />
|
||||
<button class="btn btn-primary btn-sm" @click="addProduct" :disabled="!newOilName.trim() || !newProductAmount">➕ 添加</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Oil Grid -->
|
||||
@@ -413,12 +432,15 @@ const activeCardName = ref(null)
|
||||
const activeCard = ref(null)
|
||||
|
||||
// Add oil form
|
||||
const addType = ref('oil')
|
||||
const newOilName = ref('')
|
||||
const newOilEnName = ref('')
|
||||
const newBottlePrice = ref(null)
|
||||
const newVolume = ref('5')
|
||||
const newCustomDrops = ref(null)
|
||||
const newRetailPrice = ref(null)
|
||||
const newProductAmount = ref(null)
|
||||
const newProductUnit = ref('ml')
|
||||
|
||||
// Edit oil
|
||||
const editingOilName = ref(null)
|
||||
@@ -657,6 +679,29 @@ async function addOil() {
|
||||
}
|
||||
}
|
||||
|
||||
async function addProduct() {
|
||||
if (!newOilName.value.trim() || !newProductAmount.value) return
|
||||
try {
|
||||
await oils.saveOil(
|
||||
newOilName.value.trim(),
|
||||
newBottlePrice.value || 0,
|
||||
newProductAmount.value,
|
||||
newRetailPrice.value || null,
|
||||
newOilEnName.value.trim() || null,
|
||||
newProductUnit.value
|
||||
)
|
||||
ui.showToast(`已添加: ${newOilName.value}`)
|
||||
newOilName.value = ''
|
||||
newOilEnName.value = ''
|
||||
newBottlePrice.value = null
|
||||
newProductAmount.value = null
|
||||
newProductUnit.value = 'ml'
|
||||
newRetailPrice.value = null
|
||||
} catch (e) {
|
||||
ui.showToast('添加失败: ' + (e.message || ''))
|
||||
}
|
||||
}
|
||||
|
||||
function editOil(name) {
|
||||
editingOilName.value = name
|
||||
editOilDisplayName.value = name
|
||||
@@ -1065,6 +1110,16 @@ async function saveCardImage(name) {
|
||||
}
|
||||
|
||||
/* ===== Add Oil Form ===== */
|
||||
.add-type-tabs { display: flex; gap: 0; margin-bottom: 10px; }
|
||||
.add-type-tab {
|
||||
flex: 1; padding: 6px 0; text-align: center; font-size: 13px; cursor: pointer;
|
||||
border: 1.5px solid var(--border, #d4cfc7); background: #fff; color: var(--text-mid, #6b6375);
|
||||
font-family: inherit;
|
||||
}
|
||||
.add-type-tab:first-child { border-radius: 8px 0 0 8px; }
|
||||
.add-type-tab:last-child { border-radius: 0 8px 8px 0; border-left: none; }
|
||||
.add-type-tab.active { background: var(--sage, #7a9e7e); color: #fff; border-color: var(--sage, #7a9e7e); }
|
||||
|
||||
.add-oil-form {
|
||||
margin-bottom: 16px;
|
||||
padding: 14px;
|
||||
|
||||
Reference in New Issue
Block a user