diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 34dcaaa..deee404 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -981,6 +981,44 @@ function toggleFormTag(tag) { else formTags.value.push(tag) } +/** + * Check name against public + personal recipes. + * Same name + same content → toast and return false. + * Same name + different content → show diff, prompt rename, loop until unique. + * Returns final name or false if cancelled. + */ +async function checkDupName(name, ings) { + 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 + 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 ? '公共配方库' : '我的配方' + + if (identical) { + ui.showToast(`${where}中已有一模一样的配方「${currentName}」`) + return false + } + + const existIngs = dupIngs.map(i => `${i.oil}${i.drops}滴`).join('、') + const newIngs = myIngs.map(i => `${i.oil}${i.drops}滴`).join('、') + const ok = await showConfirm( + `${where}中已有同名配方「${currentName}」,内容不同:\n\n已有:${existIngs}\n新的:${newIngs}\n\n请改名后保存`, + { okText: '改名', cancelText: '取消' } + ) + if (!ok) return false + const newName = await showPrompt('请输入新名称:', currentName) + if (!newName || !newName.trim()) return false + currentName = newName.trim() + // Loop back to check the new name + } +} + async function saveCurrentRecipe() { if (formVolume.value === 'custom' && !formCustomVolume.value) { ui.showToast('请输入自定义容量') @@ -1010,33 +1048,11 @@ async function saveCurrentRecipe() { // Dedup check for new recipes (not editing) if (!editingRecipe.value) { - const name = formName.value.trim() - // Check public library - const pubDup = recipeStore.recipes.find(r => r.name === name) - // Check personal diary - const diaryDup = diaryStore.userDiary.find(d => d.name === name) - const dup = pubDup || diaryDup - if (dup) { - const dupIngs = (dup.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) - const myIngs = cleanIngs.filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) - const identical = dupIngs.length === myIngs.length && dupIngs.every((ing, i) => ing.oil === myIngs[i].oil && ing.drops === myIngs[i].drops) - const where = pubDup ? '公共配方库' : '我的配方' - if (identical) { - ui.showToast(`${where}中已有一模一样的配方「${name}」`) - return - } - // Show difference - const existIngs = dupIngs.map(i => `${i.oil}${i.drops}滴`).join('、') - const newIngs = myIngs.map(i => `${i.oil}${i.drops}滴`).join('、') - const ok = await showConfirm( - `${where}中已有同名配方「${name}」,内容不同:\n\n已有:${existIngs}\n新的:${newIngs}\n\n是否改名后保存?`, - { okText: '改名', cancelText: '取消' } - ) - if (!ok) return - const newName = await showPrompt('请输入新名称:', name) - if (!newName || !newName.trim()) return - formName.value = newName.trim() - diaryPayload.name = newName.trim() + const result = await checkDupName(diaryPayload.name, cleanIngs) + if (result === false) return // cancelled + if (result !== diaryPayload.name) { + formName.value = result + diaryPayload.name = result } } @@ -1129,23 +1145,31 @@ async function saveParsedRecipe(index) { async function saveAllParsed() { // Sync current form edits back first syncFormToParsed() - let saved = 0 - for (let i = parsedRecipes.value.length - 1; i >= 0; i--) { + const toPublic = auth.canManage && await showConfirm('全部保存到哪里?', { okText: '公共配方库', cancelText: '个人配方' }) + let saved = 0, skipped = 0 + for (let i = 0; i < parsedRecipes.value.length; i++) { 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) + if (finalName === false) { skipped++; continue } try { - await diaryStore.createDiary({ - name: r.name.trim(), - ingredients: r.ingredients.map(i => ({ oil: i.oil, drops: i.drops })), - note: '', - tags: [], - }) + if (toPublic) { + await recipeStore.saveRecipe({ + name: finalName, + ingredients: ings.map(ing => ({ oil_name: ing.oil, drops: ing.drops })), + note: '', + tags: [], + }) + } else { + await diaryStore.createDiary({ name: finalName, ingredients: ings, note: '', tags: [] }) + } saved++ } catch {} } parsedRecipes.value = [] parsedCurrentIndex.value = -1 - ui.showToast(`已保存 ${saved} 条配方到我的配方`) + ui.showToast(`已保存 ${saved} 条配方到${toPublic ? '公共配方库' : '我的配方'}`) closeOverlay() } @@ -1424,28 +1448,10 @@ async function recommendApprove(recipe) { } async function shareDiaryToPublic(diary) { - // Check for duplicates in public library - const dup = recipeStore.recipes.find(r => r.name === diary.name) - if (dup) { - const dIngs = (diary.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) - const pIngs = (dup.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) - const identical = dIngs.length === pIngs.length && dIngs.every((ing, i) => ing.oil === pIngs[i].oil && ing.drops === pIngs[i].drops) - if (identical) { - ui.showToast('公共配方库中已有一模一样的配方「' + diary.name + '」') - return - } - // Same name, different content — show details - const existIngs = pIngs.map(i => `${i.oil}${i.drops}滴`).join('、') - const newIngs = dIngs.map(i => `${i.oil}${i.drops}滴`).join('、') - const action = await showConfirm( - `公共配方库中已有同名配方「${diary.name}」,内容不同:\n\n已有:${existIngs}\n新的:${newIngs}\n\n是否改名后共享?`, - { okText: '改名', cancelText: '取消' } - ) - if (!action) return - const newName = await showPrompt('请输入新名称:', diary.name) - if (!newName || !newName.trim()) return - diary = { ...diary, name: newName.trim() } - } + const ings = (diary.ingredients || []).map(i => ({ oil: i.oil, drops: i.drops })) + const result = await checkDupName(diary.name, ings) + if (result === false) return + if (result !== diary.name) diary = { ...diary, name: result } const ok = await showConfirm(`将「${diary.name}」共享到公共配方库?`) if (!ok) return