feat: 配方卡片容量切换、预览/保存流程优化、精油搜索自动补全、精油英文名编辑
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
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) Failing after 1m20s
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Successful in 4s
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) Failing after 1m20s
1. 配方卡片视图加回容量切换按钮(单次/2.5ml/5ml…), 非单次容量的滴数通过 Math.round 取整显示 2. 编辑器「预览」按钮改为展示当前未保存数据; 预览后点关闭询问是否保存; 直接点「保存」后留在配方卡片视图(不再关闭弹层) 3. 添加精油改为搜索输入框 + 下拉自动补全, 支持中文名和英文名筛选 4. 精油价目:添加/编辑表单加入英文名字段; 编辑/删除按钮改为悬停(桌面)或点击(移动端)才显示; 后端及数据库同步支持 oils.en_name
This commit is contained in:
@@ -75,6 +75,7 @@
|
||||
<h3 class="section-title">添加精油</h3>
|
||||
<div class="form-row">
|
||||
<input v-model="newOilName" class="form-input" placeholder="精油名称" />
|
||||
<input v-model="newOilEnName" class="form-input" placeholder="英文名 (English)" />
|
||||
<input v-model.number="newBottlePrice" class="form-input-sm" type="number" placeholder="瓶价 ¥" />
|
||||
<select v-model="newVolume" class="form-select">
|
||||
<option value="2.5">2.5ml (46滴)</option>
|
||||
@@ -129,7 +130,7 @@
|
||||
v-for="name in filteredOilNames"
|
||||
:key="name"
|
||||
class="oil-chip"
|
||||
:class="{ 'oil-chip--inactive': getMeta(name)?.isActive === false }"
|
||||
:class="{ 'oil-chip--inactive': getMeta(name)?.isActive === false, 'oil-chip--active': activeChip === name }"
|
||||
@click="openOilDetail(name)"
|
||||
>
|
||||
<span v-if="getOilCard(name)" class="oil-badge" title="有知识卡片">📖</span>
|
||||
@@ -159,7 +160,7 @@
|
||||
<div class="oil-chip-volume" v-if="getMeta(name)?.dropCount">
|
||||
{{ volumeLabel(getMeta(name).dropCount) }}
|
||||
</div>
|
||||
<div class="oil-actions" v-if="auth.canManage" @click.stop>
|
||||
<div class="oil-actions" v-if="auth.canManage" @click.stop @touchstart.stop="toggleChip(name)">
|
||||
<button class="btn-icon-sm" @click="editOil(name)" title="编辑">✏️</button>
|
||||
<button class="btn-icon-sm" @click="removeOil(name)" title="删除">🗑️</button>
|
||||
</div>
|
||||
@@ -271,6 +272,10 @@
|
||||
<button class="btn-close" @click="editingOilName = null">✕</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>英文名</label>
|
||||
<input v-model="editOilEnName" class="form-input" type="text" placeholder="English name" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>瓶价 (¥)</label>
|
||||
<input v-model.number="editBottlePrice" class="form-input" type="number" />
|
||||
@@ -334,6 +339,7 @@ const activeCard = ref(null)
|
||||
|
||||
// Add oil form
|
||||
const newOilName = ref('')
|
||||
const newOilEnName = ref('')
|
||||
const newBottlePrice = ref(null)
|
||||
const newVolume = ref('5')
|
||||
const newCustomDrops = ref(null)
|
||||
@@ -345,6 +351,14 @@ const editBottlePrice = ref(0)
|
||||
const editVolume = ref('5')
|
||||
const editDropCount = ref(0)
|
||||
const editRetailPrice = ref(null)
|
||||
const editOilEnName = ref('')
|
||||
|
||||
// Active chip (for mobile hover)
|
||||
const activeChip = ref(null)
|
||||
|
||||
function toggleChip(name) {
|
||||
activeChip.value = activeChip.value === name ? null : name
|
||||
}
|
||||
|
||||
// Volume-to-drops mapping
|
||||
const VOLUME_OPTIONS = {
|
||||
@@ -407,9 +421,13 @@ function getMeta(name) {
|
||||
}
|
||||
|
||||
function getEnglishName(name) {
|
||||
// First check the oil card for English name
|
||||
// 1. Oil card has priority
|
||||
const card = getOilCard(name)
|
||||
if (card && card.en) return card.en
|
||||
// 2. Stored en_name in meta
|
||||
const meta = oils.oilsMeta[name]
|
||||
if (meta?.enName) return meta.enName
|
||||
// 3. Static translation map
|
||||
return oilEn(name)
|
||||
}
|
||||
|
||||
@@ -466,10 +484,12 @@ async function addOil() {
|
||||
newOilName.value.trim(),
|
||||
newBottlePrice.value || 0,
|
||||
dropCount,
|
||||
newRetailPrice.value || null
|
||||
newRetailPrice.value || null,
|
||||
newOilEnName.value.trim() || null
|
||||
)
|
||||
ui.showToast(`已添加: ${newOilName.value}`)
|
||||
newOilName.value = ''
|
||||
newOilEnName.value = ''
|
||||
newBottlePrice.value = null
|
||||
newVolume.value = '5'
|
||||
newCustomDrops.value = null
|
||||
@@ -487,6 +507,7 @@ function editOil(name) {
|
||||
editVolume.value = dropCountToVolume(dc)
|
||||
editDropCount.value = dc
|
||||
editRetailPrice.value = meta?.retailPrice || null
|
||||
editOilEnName.value = meta?.enName || getEnglishName(name) || ''
|
||||
}
|
||||
|
||||
async function saveEditOil() {
|
||||
@@ -496,7 +517,8 @@ async function saveEditOil() {
|
||||
editingOilName.value,
|
||||
editBottlePrice.value,
|
||||
dropCount,
|
||||
editRetailPrice.value
|
||||
editRetailPrice.value,
|
||||
editOilEnName.value.trim() || null
|
||||
)
|
||||
ui.showToast('已更新')
|
||||
editingOilName.value = null
|
||||
@@ -982,7 +1004,8 @@ function saveContraImage() {
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
|
||||
.oil-chip:hover .oil-actions {
|
||||
.oil-chip:hover .oil-actions,
|
||||
.oil-chip--active .oil-actions {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user