diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 72e5cc5..451ca06 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -987,18 +987,18 @@ function toggleFormTag(tag) { * Same name + different content → show diff, prompt rename, loop until unique. * Returns final name or false if cancelled. */ -async function checkDupName(name, ings) { +async function checkDupName(name, ings, target = 'diary') { let currentName = name while (true) { - const pubDup = recipeStore.recipes.find(r => r.name === currentName) - const diaryDup = diaryStore.userDiary.find(d => d.name === currentName) - const dup = pubDup || diaryDup + const dup = target === 'public' + ? recipeStore.recipes.find(r => r.name === currentName) + : diaryStore.userDiary.find(d => d.name === currentName) if (!dup) return currentName const dupIngs = (dup.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) const myIngs = ings.filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) const identical = dupIngs.length === myIngs.length && dupIngs.every((d, i) => d.oil === myIngs[i].oil && d.drops === myIngs[i].drops) - const where = pubDup ? '公共配方库' : '我的配方' + const where = target === 'public' ? '公共配方库' : '我的配方' if (identical) { ui.showToast(`${where}中已有一模一样的配方「${currentName}」`) @@ -1046,45 +1046,6 @@ async function saveCurrentRecipe() { tags: formTags.value, } - // Dedup check for new recipes (not editing) - if (!editingRecipe.value) { - const result = await checkDupName(diaryPayload.name, cleanIngs) - if (result === false) { - // Skipped — but if in multi-recipe queue, load next - if (parsedCurrentIndex.value >= 0) { - const skipIdx = parsedCurrentIndex.value - // Prevent syncFormToParsed from overwriting next recipe - parsedCurrentIndex.value = -1 - parsedRecipes.value.splice(skipIdx, 1) - if (parsedRecipes.value.length > 0) { - const next = Math.min(skipIdx, parsedRecipes.value.length - 1) - parsedCurrentIndex.value = next - formName.value = parsedRecipes.value[next].name - const cocoIng = parsedRecipes.value[next].ingredients.find(i => i.oil === '椰子油') - const eoIngs = parsedRecipes.value[next].ingredients.filter(i => i.oil !== '椰子油') - formIngredients.value = eoIngs.length > 0 - ? eoIngs.map(i => ({ ...i, _search: i.oil, _open: false })) - : [{ oil: '', drops: 1, _search: '', _open: false }] - if (cocoIng) { - formCocoRow.value = { oil: '椰子油', drops: cocoIng.drops, _search: '椰子油', _open: false } - formVolume.value = 'single' - } else { - formCocoRow.value = null - formVolume.value = '' - } - ui.showToast('已跳过,请处理下一条') - } else { - closeOverlay() - } - } - return - } - if (result !== diaryPayload.name) { - formName.value = result - diaryPayload.name = result - } - } - if (editingRecipe.value && editingRecipe.value._diary_id) { // Editing an existing diary recipe try { @@ -1126,14 +1087,15 @@ async function saveCurrentRecipe() { if (auth.canManage) { const toPublic = await showConfirm('保存到哪里?', { okText: '公共配方库', cancelText: '个人配方' }) if (toPublic) { + const finalName = await dedupOrSkip(diaryPayload.name, cleanIngs, 'public') + if (!finalName) return try { - const pubPayload = { - name: formName.value.trim(), + await recipeStore.saveRecipe({ + name: finalName, ingredients: cleanIngs.map(i => ({ oil_name: i.oil, drops: i.drops })), note: formNote.value, tags: formTags.value, - } - await recipeStore.saveRecipe(pubPayload) + }) ui.showToast('已添加到公共配方库') if (!loadNextParsed()) closeOverlay() } catch (e) { @@ -1142,6 +1104,10 @@ async function saveCurrentRecipe() { return } } + const finalName = await dedupOrSkip(diaryPayload.name, cleanIngs, 'diary') + if (!finalName) return + diaryPayload.name = finalName + formName.value = finalName try { await diaryStore.createDiary(diaryPayload) ui.showToast('已添加到我的配方') @@ -1180,7 +1146,7 @@ async function saveAllParsed() { const r = parsedRecipes.value[i] if (!r.name.trim() || r.ingredients.length === 0) continue const ings = r.ingredients.map(ing => ({ oil: ing.oil, drops: ing.drops })) - const finalName = await checkDupName(r.name.trim(), ings) + const finalName = await checkDupName(r.name.trim(), ings, toPublic ? 'public' : 'diary') if (finalName === false) { skipped++; continue } try { if (toPublic) { @@ -1202,6 +1168,48 @@ async function saveAllParsed() { closeOverlay() } +/** Skip current parsed recipe and load next, or close if none left. */ +function skipCurrentParsed() { + if (parsedCurrentIndex.value < 0) return + const skipIdx = parsedCurrentIndex.value + parsedCurrentIndex.value = -1 + parsedRecipes.value.splice(skipIdx, 1) + if (parsedRecipes.value.length > 0) { + const next = Math.min(skipIdx, parsedRecipes.value.length - 1) + parsedCurrentIndex.value = next + const r = parsedRecipes.value[next] + formName.value = r.name + const cocoIng = r.ingredients.find(i => i.oil === '椰子油') + const eoIngs = r.ingredients.filter(i => i.oil !== '椰子油') + formIngredients.value = eoIngs.length > 0 + ? eoIngs.map(i => ({ ...i, _search: i.oil, _open: false })) + : [{ oil: '', drops: 1, _search: '', _open: false }] + if (cocoIng) { + formCocoRow.value = { oil: '椰子油', drops: cocoIng.drops, _search: '椰子油', _open: false } + formVolume.value = 'single' + } else { + formCocoRow.value = null + formVolume.value = '' + } + ui.showToast('已跳过,请处理下一条') + } else { + closeOverlay() + } +} + +/** + * Run dedup check for saveCurrentRecipe. Returns final name or null if should stop. + */ +async function dedupOrSkip(name, ings, target) { + if (editingRecipe.value) return name + const result = await checkDupName(name, ings, target) + if (result === false) { + if (parsedCurrentIndex.value >= 0) skipCurrentParsed() + return null + } + return result +} + /** After saving, mark current as done and load next. Returns true if there's a next one. */ function loadNextParsed() { if (parsedCurrentIndex.value < 0 || parsedRecipes.value.length === 0) return false @@ -1478,7 +1486,7 @@ async function recommendApprove(recipe) { async function shareDiaryToPublic(diary) { const ings = (diary.ingredients || []).map(i => ({ oil: i.oil, drops: i.drops })) - const result = await checkDupName(diary.name, ings) + const result = await checkDupName(diary.name, ings, 'public') if (result === false) return if (result !== diary.name) diary = { ...diary, name: result }