fix: 去重只检查目标库,跳过后继续处理下一条
Some checks failed
PR Preview / teardown-preview (pull_request) Has been skipped
Test / unit-test (push) Failing after 6s
Test / e2e-test (push) Has been skipped
Test / build-check (push) Successful in 4s
PR Preview / test (pull_request) Failing after 5s
PR Preview / deploy-preview (pull_request) Has been skipped

- checkDupName 接受 target 参数,只查目标库(公共/个人)
- 提取 skipCurrentParsed/dedupOrSkip 避免代码重复
- 共享到公共库检查公共库,保存到个人检查个人

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-11 22:59:00 +00:00
parent 341cdb60bf
commit f99d377027

View File

@@ -987,18 +987,18 @@ function toggleFormTag(tag) {
* Same name + different content → show diff, prompt rename, loop until unique. * Same name + different content → show diff, prompt rename, loop until unique.
* Returns final name or false if cancelled. * Returns final name or false if cancelled.
*/ */
async function checkDupName(name, ings) { async function checkDupName(name, ings, target = 'diary') {
let currentName = name let currentName = name
while (true) { while (true) {
const pubDup = recipeStore.recipes.find(r => r.name === currentName) const dup = target === 'public'
const diaryDup = diaryStore.userDiary.find(d => d.name === currentName) ? recipeStore.recipes.find(r => r.name === currentName)
const dup = pubDup || diaryDup : diaryStore.userDiary.find(d => d.name === currentName)
if (!dup) return currentName if (!dup) return currentName
const dupIngs = (dup.ingredients || []).filter(i => i.oil).sort((a, b) => a.oil.localeCompare(b.oil)) 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 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 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) { if (identical) {
ui.showToast(`${where}中已有一模一样的配方「${currentName}`) ui.showToast(`${where}中已有一模一样的配方「${currentName}`)
@@ -1046,45 +1046,6 @@ async function saveCurrentRecipe() {
tags: formTags.value, 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) { if (editingRecipe.value && editingRecipe.value._diary_id) {
// Editing an existing diary recipe // Editing an existing diary recipe
try { try {
@@ -1126,14 +1087,15 @@ async function saveCurrentRecipe() {
if (auth.canManage) { if (auth.canManage) {
const toPublic = await showConfirm('保存到哪里?', { okText: '公共配方库', cancelText: '个人配方' }) const toPublic = await showConfirm('保存到哪里?', { okText: '公共配方库', cancelText: '个人配方' })
if (toPublic) { if (toPublic) {
const finalName = await dedupOrSkip(diaryPayload.name, cleanIngs, 'public')
if (!finalName) return
try { try {
const pubPayload = { await recipeStore.saveRecipe({
name: formName.value.trim(), name: finalName,
ingredients: cleanIngs.map(i => ({ oil_name: i.oil, drops: i.drops })), ingredients: cleanIngs.map(i => ({ oil_name: i.oil, drops: i.drops })),
note: formNote.value, note: formNote.value,
tags: formTags.value, tags: formTags.value,
} })
await recipeStore.saveRecipe(pubPayload)
ui.showToast('已添加到公共配方库') ui.showToast('已添加到公共配方库')
if (!loadNextParsed()) closeOverlay() if (!loadNextParsed()) closeOverlay()
} catch (e) { } catch (e) {
@@ -1142,6 +1104,10 @@ async function saveCurrentRecipe() {
return return
} }
} }
const finalName = await dedupOrSkip(diaryPayload.name, cleanIngs, 'diary')
if (!finalName) return
diaryPayload.name = finalName
formName.value = finalName
try { try {
await diaryStore.createDiary(diaryPayload) await diaryStore.createDiary(diaryPayload)
ui.showToast('已添加到我的配方') ui.showToast('已添加到我的配方')
@@ -1180,7 +1146,7 @@ async function saveAllParsed() {
const r = parsedRecipes.value[i] const r = parsedRecipes.value[i]
if (!r.name.trim() || r.ingredients.length === 0) continue if (!r.name.trim() || r.ingredients.length === 0) continue
const ings = r.ingredients.map(ing => ({ oil: ing.oil, drops: ing.drops })) 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 } if (finalName === false) { skipped++; continue }
try { try {
if (toPublic) { if (toPublic) {
@@ -1202,6 +1168,48 @@ async function saveAllParsed() {
closeOverlay() 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. */ /** After saving, mark current as done and load next. Returns true if there's a next one. */
function loadNextParsed() { function loadNextParsed() {
if (parsedCurrentIndex.value < 0 || parsedRecipes.value.length === 0) return false if (parsedCurrentIndex.value < 0 || parsedRecipes.value.length === 0) return false
@@ -1478,7 +1486,7 @@ async function recommendApprove(recipe) {
async function shareDiaryToPublic(diary) { async function shareDiaryToPublic(diary) {
const ings = (diary.ingredients || []).map(i => ({ oil: i.oil, drops: i.drops })) 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 === false) return
if (result !== diary.name) diary = { ...diary, name: result } if (result !== diary.name) diary = { ...diary, name: result }