diff --git a/frontend/src/composables/useSmartPaste.js b/frontend/src/composables/useSmartPaste.js index 8352681..a609767 100644 --- a/frontend/src/composables/useSmartPaste.js +++ b/frontend/src/composables/useSmartPaste.js @@ -266,7 +266,41 @@ export function parseSingleBlock(raw, oilNames) { * appears after some oils have been found, it starts a new recipe. */ export function parseMultiRecipes(raw, oilNames) { - const parts = raw.split(/[,,、\n\r]+/).map(s => s.trim()).filter(s => s) + // First split by lines/commas, then within each part also try space splitting + const roughParts = raw.split(/[,,、\n\r]+/).map(s => s.trim()).filter(s => s) + const parts = [] + for (const rp of roughParts) { + // If the part has spaces and contains mixed name+oil, split by spaces too + // But only if spaces actually separate meaningful chunks + const spaceParts = rp.split(/\s+/).filter(s => s) + if (spaceParts.length > 1) { + parts.push(...spaceParts) + } else { + // No spaces or single chunk — try to separate name prefix from oil+number + // e.g. "长高芳香调理8" → check if any oil is inside + const hasOilInside = oilNames.some(oil => rp.includes(oil)) + if (hasOilInside && rp.length > 2) { + // Find the earliest oil match position + let earliest = rp.length + let earliestOil = '' + for (const oil of oilNames) { + const pos = rp.indexOf(oil) + if (pos >= 0 && pos < earliest) { + earliest = pos + earliestOil = oil + } + } + if (earliest > 0) { + parts.push(rp.substring(0, earliest)) + parts.push(rp.substring(earliest)) + } else { + parts.push(rp) + } + } else { + parts.push(rp) + } + } + } const recipes = [] let current = { nameParts: [], ingredientParts: [], foundOil: false } diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 4a96429..6cd0750 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -520,16 +520,17 @@ async function saveCurrentRecipe() { } const cleanIngs = validIngs.map(i => ({ oil: i.oil, drops: i.drops })) + const diaryPayload = { + name: formName.value.trim(), + ingredients: cleanIngs, + note: formNote.value, + tags: formTags.value, + } if (editingRecipe.value && editingRecipe.value._diary_id) { - // Editing a diary (personal) recipe + // Editing an existing diary recipe try { - await diaryStore.updateDiary(editingRecipe.value._diary_id, { - name: formName.value.trim(), - ingredients: cleanIngs, - note: formNote.value, - tags: formTags.value, - }) + await diaryStore.updateDiary(editingRecipe.value._diary_id, diaryPayload) ui.showToast('个人配方已更新') closeOverlay() } catch (e) { @@ -538,22 +539,30 @@ async function saveCurrentRecipe() { return } - // Public recipe: API expects oil_name - const payload = { - name: formName.value.trim(), - ingredients: cleanIngs.map(i => ({ oil_name: i.oil, drops: i.drops })), - note: formNote.value, - tags: formTags.value, - } - - if (editingRecipe.value) { - payload._id = editingRecipe.value._id - payload._version = editingRecipe.value._version + if (editingRecipe.value && editingRecipe.value._id) { + // Editing an existing public recipe + const payload = { + _id: editingRecipe.value._id, + _version: editingRecipe.value._version, + name: formName.value.trim(), + ingredients: cleanIngs.map(i => ({ oil_name: i.oil, drops: i.drops })), + note: formNote.value, + tags: formTags.value, + } + try { + await recipeStore.saveRecipe(payload) + ui.showToast('配方已更新') + closeOverlay() + } catch (e) { + ui.showToast('保存失败: ' + (e.message || '未知错误')) + } + return } + // New recipe: always save to diary (personal) try { - await recipeStore.saveRecipe(payload) - ui.showToast(editingRecipe.value ? '配方已更新' : '配方已添加') + await diaryStore.createDiary(diaryPayload) + ui.showToast('已添加到我的配方') closeOverlay() } catch (e) { ui.showToast('保存失败: ' + (e.message || '未知错误'))