feat: Header重排、共享配方到公共库、待审核配方、权限优化 #17

Merged
fam merged 39 commits from fix/ui-polish-round2 into main 2026-04-09 18:37:12 +00:00
2 changed files with 36 additions and 23 deletions
Showing only changes of commit 4826c00e27 - Show all commits

View File

@@ -597,18 +597,33 @@ function copyText() {
async function applyTranslation() {
showTranslationEditor.value = false
// Persist en_name to backend
let saved = 0
// 1. Save recipe English name
if (recipe.value._id && customRecipeNameEn.value) {
try {
await api.put(`/api/recipes/${recipe.value._id}`, {
en_name: customRecipeNameEn.value,
version: recipe.value._version,
})
ui.showToast('翻译已保存')
} catch (e) {
ui.showToast('翻译保存失败')
}
recipe.value.en_name = customRecipeNameEn.value
saved++
} 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
nextTick(() => generateCardImage())
}
@@ -616,7 +631,7 @@ async function applyTranslation() {
// Override translation getters for card rendering
function getCardOilName(name) {
if (cardLang.value === 'en') {
return customOilNameEn.value[name] || oilEn(name) || name
return customOilNameEn.value[name] || oilsStore.oilsMeta[name]?.enName || oilEn(name) || name
}
return name
}

View File

@@ -257,7 +257,7 @@
<!-- Edit Oil Overlay -->
<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">
<h3>{{ editingOilName }}</h3>
<button class="btn-close" @click="editingOilName = null"></button>
@@ -477,8 +477,10 @@ function chipStyle(name) {
function isIncomplete(name) {
const meta = getMeta(name)
if (!meta) return true
// Incomplete if missing bottle price, drop count, or retail price
return !meta.bottlePrice || !meta.dropCount || !meta.retailPrice
if (meta.isActive === false) return false // 下架的不算不全
// Incomplete: missing English name, retail price, or bottle price
const hasEn = meta.enName || getEnglishName(name)
return !meta.bottlePrice || !meta.retailPrice || !hasEn
}
function getEffectiveDropCount() {
@@ -675,7 +677,7 @@ async function toggleOilActive() {
const meta = getMeta(name)
const newActive = meta?.isActive === false ? 1 : 0
try {
await api('/api/oils', {
const res = await api('/api/oils', {
method: 'POST',
body: JSON.stringify({
name,
@@ -685,12 +687,17 @@ async function toggleOilActive() {
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 {
ui.showToast('操作失败')
} catch (e) {
ui.showToast('操作失败: ' + (e.message || ''))
}
}
@@ -1201,24 +1208,15 @@ async function saveCardImage(name) {
background: #fff5f5 !important;
}
.oil-name-line {
font-size: 14px;
font-size: clamp(10px, 2.5vw, 14px);
font-weight: 500;
color: var(--text-dark);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.oil-en-line {
font-size: 10px;
font-size: clamp(8px, 1.8vw, 10px);
color: var(--text-light);
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 {