diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 4654118..3b3269f 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -29,8 +29,8 @@ 共{{ totalSelected }}个 @@ -62,9 +59,17 @@ +
+ + + + +
+

+ 📖 我的配方 ({{ myRecipes.length }}) 已贡献 {{ sharedCount.adopted }}/{{ sharedCount.total }} 条 {{ showMyRecipes ? '▾' : '▸' }} @@ -107,6 +112,7 @@

+ 🌿 公共配方库 ({{ publicRecipes.length }}) {{ showPublicRecipes ? '▾' : '▸' }}

@@ -541,29 +547,40 @@ function toggleDiarySelect(id) { function clearSelection() { selectedIds.clear() selectedDiaryIds.clear() - batchAction.value = '' + showBatchMenu.value = false } -function onBatchSelect() { - if (batchAction.value) { - executeBatchAction(batchAction.value) - batchAction.value = '' +function doBatch(action) { + showBatchMenu.value = false + executeBatchAction(action) +} + +function toggleSelectAll() { + if (isAllSelected.value) { + clearSelection() + } else { + myFilteredRecipes.value.forEach(d => selectedDiaryIds.add(d.id)) + if (auth.canEdit) publicFilteredRecipes.value.forEach(r => selectedIds.add(r._id)) + showMyRecipes.value = true + if (auth.canEdit) showPublicRecipes.value = true } } -function toggleSelectAllDiary() { - if (selectedDiaryIds.size > 0 || selectedIds.size > 0) { - // Any selected → deselect all +function toggleMySelect() { + if (isMyAllSelected.value) { selectedDiaryIds.clear() + } else { + myFilteredRecipes.value.forEach(d => selectedDiaryIds.add(d.id)) + showMyRecipes.value = true + } +} + +function togglePubSelect() { + if (isPubAllSelected.value) { selectedIds.clear() } else { - // Select all - myFilteredRecipes.value.forEach(d => selectedDiaryIds.add(d.id)) - if (auth.canEdit) { - publicFilteredRecipes.value.forEach(r => selectedIds.add(r._id)) - } - showMyRecipes.value = true - if (auth.canEdit) showPublicRecipes.value = true + publicFilteredRecipes.value.forEach(r => selectedIds.add(r._id)) + showPublicRecipes.value = true } } @@ -958,8 +975,15 @@ async function saveAllParsed() { const sharedCount = ref({ adopted: 0, total: 0 }) const previewRecipeIndex = ref(null) -const batchAction = ref('') +const showBatchMenu = ref(false) const totalSelected = computed(() => selectedIds.size + selectedDiaryIds.size) +const isMyAllSelected = computed(() => myFilteredRecipes.value.length > 0 && selectedDiaryIds.size === myFilteredRecipes.value.length) +const isPubAllSelected = computed(() => publicFilteredRecipes.value.length > 0 && selectedIds.size === publicFilteredRecipes.value.length) +const isAllSelected = computed(() => { + const myOk = myFilteredRecipes.value.length > 0 && isMyAllSelected.value + const pubOk = !auth.canEdit || (publicFilteredRecipes.value.length > 0 && isPubAllSelected.value) + return myOk && pubOk +}) const showMyRecipes = ref(false) const showPublicRecipes = ref(false) const showReviewHistory = ref(false) @@ -1609,6 +1633,21 @@ watch(() => recipeStore.recipes, () => { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-bottom: 8px; } .select-count { font-size: 12px; color: #4a9d7e; font-weight: 500; white-space: nowrap; } +.batch-menu { display: flex; gap: 6px; flex-wrap: wrap; margin-bottom: 8px; } +.batch-menu-btn { + padding: 5px 12px; border: 1.5px solid #e5e4e7; border-radius: 8px; background: #fff; + font-size: 12px; cursor: pointer; font-family: inherit; color: #6b6375; +} +.batch-menu-btn:hover { border-color: #7ec6a4; color: #4a9d7e; } +.batch-delete { color: #c0392b; border-color: #e8b4b0; } +.batch-delete:hover { background: #fdf0ee; border-color: #c0392b; } +.mini-select { + width: 18px; height: 18px; border: 1.5px solid #d4cfc7; border-radius: 4px; + background: #fff; color: transparent; font-size: 11px; cursor: pointer; + display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; + padding: 0; margin-right: 4px; line-height: 1; +} +.mini-select.active { background: #4a9d7e; border-color: #4a9d7e; color: #fff; } .tag-list-bar { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; padding: 8px 0; }