fix: 精油名不截断改用clamp缩放、下架错误提示、翻译双向同步
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 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 1m27s
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 4s
PR Preview / deploy-preview (pull_request) Successful in 14s
Test / e2e-test (push) Failing after 1m27s
精油名: - 用 font-size:clamp() 自适应缩小,不截断不换行 - 去掉 overflow:hidden/text-overflow:ellipsis 信息不全判定: - 缺英文名、零售价、或会员价 = 红色底色 - 下架的不算不全 - 补全后自动恢复 下架功能: - 修复:添加详细错误信息显示 - 编辑弹窗宽度恢复到默认520px(不再限制400px) 翻译双向同步: - 配方卡片修改翻译 → 同时保存到 oils.en_name(oilsStore.saveOil) - 精油价目页修改英文名 → 保存到 oils.en_name - 两处共用同一个DB字段,loadOils后自动同步 - getCardOilName fallback链:custom → oilsMeta.enName → oilEn → name Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -597,18 +597,33 @@ function copyText() {
|
|||||||
|
|
||||||
async function applyTranslation() {
|
async function applyTranslation() {
|
||||||
showTranslationEditor.value = false
|
showTranslationEditor.value = false
|
||||||
// Persist en_name to backend
|
let saved = 0
|
||||||
|
|
||||||
|
// 1. Save recipe English name
|
||||||
if (recipe.value._id && customRecipeNameEn.value) {
|
if (recipe.value._id && customRecipeNameEn.value) {
|
||||||
try {
|
try {
|
||||||
await api.put(`/api/recipes/${recipe.value._id}`, {
|
await api.put(`/api/recipes/${recipe.value._id}`, {
|
||||||
en_name: customRecipeNameEn.value,
|
en_name: customRecipeNameEn.value,
|
||||||
version: recipe.value._version,
|
version: recipe.value._version,
|
||||||
})
|
})
|
||||||
ui.showToast('翻译已保存')
|
recipe.value.en_name = customRecipeNameEn.value
|
||||||
} catch (e) {
|
saved++
|
||||||
ui.showToast('翻译保存失败')
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Save each oil's English name to oils table (syncs with oil reference page)
|
||||||
|
for (const [oilName, enName] of Object.entries(customOilNameEn.value)) {
|
||||||
|
if (!enName?.trim()) continue
|
||||||
|
const meta = oilsStore.oilsMeta[oilName]
|
||||||
|
if (!meta || meta.enName === enName.trim()) continue
|
||||||
|
try {
|
||||||
|
await oilsStore.saveOil(oilName, meta.bottlePrice, meta.dropCount, meta.retailPrice, enName.trim())
|
||||||
|
saved++
|
||||||
|
} catch {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (saved > 0) ui.showToast(`翻译已保存(${saved}项)`)
|
||||||
|
|
||||||
cardImageUrl.value = null
|
cardImageUrl.value = null
|
||||||
nextTick(() => generateCardImage())
|
nextTick(() => generateCardImage())
|
||||||
}
|
}
|
||||||
@@ -616,7 +631,7 @@ async function applyTranslation() {
|
|||||||
// Override translation getters for card rendering
|
// Override translation getters for card rendering
|
||||||
function getCardOilName(name) {
|
function getCardOilName(name) {
|
||||||
if (cardLang.value === 'en') {
|
if (cardLang.value === 'en') {
|
||||||
return customOilNameEn.value[name] || oilEn(name) || name
|
return customOilNameEn.value[name] || oilsStore.oilsMeta[name]?.enName || oilEn(name) || name
|
||||||
}
|
}
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -257,7 +257,7 @@
|
|||||||
|
|
||||||
<!-- Edit Oil Overlay -->
|
<!-- Edit Oil Overlay -->
|
||||||
<div v-if="editingOilName" class="modal-overlay" @click.self="editingOilName = null">
|
<div v-if="editingOilName" class="modal-overlay" @click.self="editingOilName = null">
|
||||||
<div class="modal-panel" style="max-width:400px">
|
<div class="modal-panel">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h3>{{ editingOilName }}</h3>
|
<h3>{{ editingOilName }}</h3>
|
||||||
<button class="btn-close" @click="editingOilName = null">✕</button>
|
<button class="btn-close" @click="editingOilName = null">✕</button>
|
||||||
@@ -477,8 +477,10 @@ function chipStyle(name) {
|
|||||||
function isIncomplete(name) {
|
function isIncomplete(name) {
|
||||||
const meta = getMeta(name)
|
const meta = getMeta(name)
|
||||||
if (!meta) return true
|
if (!meta) return true
|
||||||
// Incomplete if missing bottle price, drop count, or retail price
|
if (meta.isActive === false) return false // 下架的不算不全
|
||||||
return !meta.bottlePrice || !meta.dropCount || !meta.retailPrice
|
// Incomplete: missing English name, retail price, or bottle price
|
||||||
|
const hasEn = meta.enName || getEnglishName(name)
|
||||||
|
return !meta.bottlePrice || !meta.retailPrice || !hasEn
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEffectiveDropCount() {
|
function getEffectiveDropCount() {
|
||||||
@@ -675,7 +677,7 @@ async function toggleOilActive() {
|
|||||||
const meta = getMeta(name)
|
const meta = getMeta(name)
|
||||||
const newActive = meta?.isActive === false ? 1 : 0
|
const newActive = meta?.isActive === false ? 1 : 0
|
||||||
try {
|
try {
|
||||||
await api('/api/oils', {
|
const res = await api('/api/oils', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
name,
|
name,
|
||||||
@@ -685,12 +687,17 @@ async function toggleOilActive() {
|
|||||||
is_active: newActive,
|
is_active: newActive,
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
if (!res.ok) {
|
||||||
|
const err = await res.json().catch(() => ({}))
|
||||||
|
ui.showToast('操作失败: ' + (err.detail || res.status))
|
||||||
|
return
|
||||||
|
}
|
||||||
await oils.loadOils()
|
await oils.loadOils()
|
||||||
cardVersion.value++
|
cardVersion.value++
|
||||||
ui.showToast(newActive ? '已重新上架' : '已下架')
|
ui.showToast(newActive ? '已重新上架' : '已下架')
|
||||||
editingOilName.value = null
|
editingOilName.value = null
|
||||||
} catch {
|
} catch (e) {
|
||||||
ui.showToast('操作失败')
|
ui.showToast('操作失败: ' + (e.message || ''))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1201,24 +1208,15 @@ async function saveCardImage(name) {
|
|||||||
background: #fff5f5 !important;
|
background: #fff5f5 !important;
|
||||||
}
|
}
|
||||||
.oil-name-line {
|
.oil-name-line {
|
||||||
font-size: 14px;
|
font-size: clamp(10px, 2.5vw, 14px);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
color: var(--text-dark);
|
color: var(--text-dark);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
}
|
||||||
.oil-en-line {
|
.oil-en-line {
|
||||||
font-size: 10px;
|
font-size: clamp(8px, 1.8vw, 10px);
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
/* Shrink name for long oils */
|
|
||||||
@container (max-width: 180px) {
|
|
||||||
.oil-name-line { font-size: 12px; }
|
|
||||||
.oil-en-line { font-size: 9px; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.oil-chip-actions {
|
.oil-chip-actions {
|
||||||
|
|||||||
Reference in New Issue
Block a user