Merge branch 'dev' into feature/qr-upload-hint
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / e2e-test (push) Has been cancelled
Test / build-check (push) Has been cancelled
Test / unit-test (push) Has been cancelled
PR Preview / test (pull_request) Successful in 4s
PR Preview / deploy-preview (pull_request) Successful in 14s

# Conflicts:
#	frontend/src/components/RecipeDetailOverlay.vue
This commit is contained in:
2026-04-07 22:25:15 +00:00
5 changed files with 42 additions and 12 deletions

View File

@@ -119,7 +119,7 @@ async function submit() {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.35);
z-index: 5000;
z-index: 6000;
display: flex;
align-items: center;
justify-content: center;

View File

@@ -36,6 +36,17 @@
>English</button>
</div>
<!-- Volume selector -->
<div class="volume-controls card-volume-controls">
<button
v-for="(drops, ml) in VOLUME_DROPS"
:key="ml"
class="volume-btn"
:class="{ active: selectedCardVolume === ml }"
@click="onCardVolumeChange(ml)"
>{{ ml === '单次' ? '单次' : ml + 'ml' }}</button>
</div>
<!-- QR / brand upload hint -->
<div v-if="showBrandHint" class="brand-upload-hint">
<span class="hint-icon"></span>
@@ -382,6 +393,7 @@ const viewMode = ref('card')
const cardRef = ref(null)
const cardImageUrl = ref(null)
const cardLang = ref('zh')
const selectedCardVolume = ref('单次')
const showTranslationEditor = ref(false)
const customRecipeNameEn = ref('')
const customOilNameEn = ref({})
@@ -547,9 +559,20 @@ function copyText() {
})
}
function applyTranslation() {
// translations stored in customOilNameEn / customRecipeNameEn
async function applyTranslation() {
showTranslationEditor.value = false
// Persist en_name to backend
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('翻译保存失败')
}
}
cardImageUrl.value = null
nextTick(() => generateCardImage())
}
@@ -564,7 +587,7 @@ function getCardOilName(name) {
function getCardRecipeName() {
if (cardLang.value === 'en') {
return customRecipeNameEn.value || recipeNameEn(recipe.value.name)
return customRecipeNameEn.value || recipe.value.en_name || recipeNameEn(recipe.value.name)
}
return recipe.value.name
}
@@ -669,7 +692,7 @@ onMounted(() => {
editTags.value = [...(r.tags || [])]
editIngredients.value = (r.ingredients || []).map(i => ({ oil: i.oil, drops: i.drops }))
// Init translation defaults
customRecipeNameEn.value = recipeNameEn(r.name)
customRecipeNameEn.value = r.en_name || recipeNameEn(r.name)
const enMap = {}
;(r.ingredients || []).forEach(ing => {
enMap[ing.oil] = oilEn(ing.oil) || ing.oil

View File

@@ -16,6 +16,7 @@ export const useRecipesStore = defineStore('recipes', () => {
_owner_name: r._owner_name ?? r.owner_name ?? '',
_version: r._version ?? r.version ?? 1,
name: r.name,
en_name: r.en_name ?? '',
note: r.note ?? '',
tags: r.tags ?? [],
ingredients: (r.ingredients ?? []).map((ing) => ({