fix: 字号恢复正常大小、下架改用api.post、翻译编辑器预填充
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 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 1m26s

精油价目:
- 字号恢复固定大小(14/10/13/11px),手机端@media缩小
- 不再用clamp()(之前太小)
- 下架改用 api.post 替代 api() raw fetch,更可靠
- 稀释比例/使用禁忌卡片: emoji和标题合并为一行(flex row)

翻译同步:
- 打开翻译编辑器时预填充: 读取 oilsMeta.enName → oilEn() → 填入输入框
- 用户看到当前英文名,修改后保存到 oils.en_name
- 精油价目页 getEnglishName 读同一字段,自动同步

翻译表:
- 补充 舒缓→Deep Blue 等常用精油英文名
- oilEn() 支持去掉/添加"复方"后缀匹配

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-09 16:38:04 +00:00
parent 3912e2d122
commit 73a041d9c8
2 changed files with 44 additions and 29 deletions

View File

@@ -103,7 +103,7 @@
<button
v-if="cardLang === 'en' && authStore.canManage"
class="action-btn"
@click="showTranslationEditor = true"
@click="openTranslationEditor"
> 修改翻译</button>
<button
v-if="showBrandHint"
@@ -595,6 +595,18 @@ function copyText() {
})
}
function openTranslationEditor() {
// Pre-populate with existing English names from DB/translation table
const map = {}
for (const ing of cardIngredients.value) {
const existing = oilsStore.oilsMeta[ing.oil]?.enName || oilEn(ing.oil)
if (existing) map[ing.oil] = existing
}
customOilNameEn.value = map
customRecipeNameEn.value = recipe.value.en_name || recipeNameEn(recipe.value.name)
showTranslationEditor.value = true
}
async function applyTranslation() {
showTranslationEditor.value = false
let saved = 0

View File

@@ -2,15 +2,19 @@
<div class="oil-reference">
<!-- Knowledge Cards at Top -->
<div style="display:flex;gap:10px;margin-bottom:16px;flex-wrap:wrap">
<div @click="showDilution = true" style="flex:1;min-width:140px;background:linear-gradient(135deg,#e8f5e9,#c8e6c9);border-radius:14px;padding:16px;cursor:pointer;transition:transform 0.2s" @mouseover="$event.target.style.transform='translateY(-2px)'" @mouseout="$event.target.style.transform=''">
<div style="font-size:24px;margin-bottom:6px">💧</div>
<div style="font-size:14px;font-weight:600;color:#2e7d32">稀释比例</div>
<div style="font-size:11px;color:#558b2f;margin-top:4px">不同年龄段的稀释指南</div>
<div @click="showDilution = true" style="flex:1;min-width:140px;background:linear-gradient(135deg,#e8f5e9,#c8e6c9);border-radius:12px;padding:12px 16px;cursor:pointer;transition:transform 0.2s;display:flex;align-items:center;gap:10px" @mouseover="$event.currentTarget.style.transform='translateY(-2px)'" @mouseout="$event.currentTarget.style.transform=''">
<span style="font-size:22px">💧</span>
<div>
<div style="font-size:14px;font-weight:600;color:#2e7d32">稀释比例</div>
<div style="font-size:11px;color:#558b2f;margin-top:2px">不同年龄段的稀释指南</div>
</div>
</div>
<div @click="showContra = true" style="flex:1;min-width:140px;background:linear-gradient(135deg,#fff8e1,#ffecb3);border-radius:14px;padding:16px;cursor:pointer;transition:transform 0.2s" @mouseover="$event.target.style.transform='translateY(-2px)'" @mouseout="$event.target.style.transform=''">
<div style="font-size:24px;margin-bottom:6px"></div>
<div style="font-size:14px;font-weight:600;color:#f57f17">使用禁忌</div>
<div style="font-size:11px;color:#ff8f00;margin-top:4px">安全使用精油的注意事项</div>
<div @click="showContra = true" style="flex:1;min-width:140px;background:linear-gradient(135deg,#fff8e1,#ffecb3);border-radius:12px;padding:12px 16px;cursor:pointer;transition:transform 0.2s;display:flex;align-items:center;gap:10px" @mouseover="$event.currentTarget.style.transform='translateY(-2px)'" @mouseout="$event.currentTarget.style.transform=''">
<span style="font-size:22px"></span>
<div>
<div style="font-size:14px;font-weight:600;color:#f57f17">使用禁忌</div>
<div style="font-size:11px;color:#ff8f00;margin-top:2px">安全使用精油的注意事项</div>
</div>
</div>
</div>
@@ -673,27 +677,20 @@ async function toggleOilActive() {
const meta = getMeta(name)
const newActive = meta?.isActive === false ? 1 : 0
try {
const res = await api('/api/oils', {
method: 'POST',
body: JSON.stringify({
name,
bottle_price: meta?.bottlePrice || 0,
drop_count: meta?.dropCount || 1,
retail_price: meta?.retailPrice,
is_active: newActive,
}),
await api.post('/api/oils', {
name,
bottle_price: meta?.bottlePrice || 0,
drop_count: meta?.dropCount || 1,
retail_price: meta?.retailPrice || null,
en_name: meta?.enName || null,
is_active: newActive,
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
ui.showToast('操作失败: ' + (err.detail || res.status))
return
}
await oils.loadOils()
cardVersion.value++
ui.showToast(newActive ? '已重新上架' : '已下架')
editingOilName.value = null
} catch (e) {
ui.showToast('操作失败: ' + (e.message || ''))
ui.showToast('操作失败: ' + (e.message || e))
}
}
@@ -1206,33 +1203,39 @@ async function saveCardImage(name) {
background: #fff5f5 !important;
}
.oil-name-line {
font-size: clamp(10px, 2.5vw, 14px);
font-size: 14px;
font-weight: 500;
color: var(--text-dark);
white-space: nowrap;
}
.oil-en-line {
font-size: clamp(8px, 1.8vw, 10px);
font-size: 10px;
color: var(--text-light);
white-space: nowrap;
}
.oil-price-line {
font-size: clamp(10px, 2.2vw, 13px);
font-size: 13px;
color: var(--sage-dark);
font-weight: 600;
white-space: nowrap;
}
.oil-price-unit {
font-size: clamp(8px, 1.6vw, 10px);
font-size: 10px;
font-weight: 400;
color: var(--text-light);
}
.oil-retail-line {
font-size: clamp(8px, 1.6vw, 11px);
font-size: 11px;
color: var(--text-light);
text-decoration: line-through;
white-space: nowrap;
}
@media (max-width: 480px) {
.oil-name-line { font-size: 12px; }
.oil-en-line { font-size: 9px; }
.oil-price-line { font-size: 11px; }
.oil-retail-line { font-size: 9px; }
}
.oil-chip-actions {
position: absolute;