diff --git a/backend/main.py b/backend/main.py index 0a78a20..18a7bea 100644 --- a/backend/main.py +++ b/backend/main.py @@ -824,9 +824,7 @@ def _check_recipe_permission(conn, recipe_id, user): row = conn.execute("SELECT owner_id, name FROM recipes WHERE id = ?", (recipe_id,)).fetchone() if not row: raise HTTPException(404, "Recipe not found") - if user["role"] in ("admin", "senior_editor"): - return row - if user["role"] in ("editor",) and row["owner_id"] == user.get("id"): + if user["role"] in ("admin", "senior_editor", "editor"): return row raise HTTPException(403, "权限不足") diff --git a/frontend/src/stores/auth.js b/frontend/src/stores/auth.js index 5f59086..d0dd0a7 100644 --- a/frontend/src/stores/auth.js +++ b/frontend/src/stores/auth.js @@ -73,10 +73,8 @@ export const useAuthStore = defineStore('auth', () => { user.value = { ...DEFAULT_USER } } - function canEditRecipe(recipe) { - if (isAdmin.value || user.value.role === 'senior_editor') return true - if (canEdit.value && recipe._owner_id === user.value.id) return true - return false + function canEditRecipe() { + return canEdit.value } return { diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 26ae57e..32a6124 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -964,6 +964,38 @@ async function saveCurrentRecipe() { tags: formTags.value, } + // 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() + } + } + if (editingRecipe.value && editingRecipe.value._diary_id) { // Editing an existing diary recipe try {