From 09a3b9b95d2a1e4567c39ac8a83f98af041cadd5 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Fri, 10 Apr 2026 15:31:49 +0000 Subject: [PATCH] =?UTF-8?q?UI:=20=E6=89=B9=E9=87=8F=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=B1=95=E5=BC=80=E8=8F=9C=E5=8D=95=EF=BC=8C?= =?UTF-8?q?=E5=90=84=E5=8C=BA=E5=9F=9F=E7=8B=AC=E7=AB=8B=E5=85=A8=E9=80=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 批量操作改为按钮点击展开菜单(打标签/导出卡片/共享/删除) - 共享到公共库仅在全选我的配方且未选公共配方时显示 - 我的配方和公共配方库各有独立的✓全选按钮 - 两个区域都全选后,顶部全选按钮激活 Co-Authored-By: Claude Opus 4.6 (1M context) --- frontend/src/views/RecipeManager.vue | 84 ++++++++++++++++++---------- 1 file changed, 56 insertions(+), 28 deletions(-) diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue index 4654118..06edcf7 100644 --- a/frontend/src/views/RecipeManager.vue +++ b/frontend/src/views/RecipeManager.vue @@ -29,25 +29,25 @@ 共{{ totalSelected }}个 - - + + +
+ + + + +

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

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

@@ -541,29 +543,35 @@ 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 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 +966,11 @@ 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(() => isMyAllSelected.value && (!auth.canEdit || isPubAllSelected.value)) const showMyRecipes = ref(false) const showPublicRecipes = ref(false) const showReviewHistory = ref(false) @@ -1609,6 +1620,23 @@ 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; padding: 8px 0; +} +.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: 20px; height: 20px; border: 1.5px solid #d4cfc7; border-radius: 4px; + background: #fff; color: transparent; font-size: 12px; cursor: pointer; + display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; + margin-right: 4px; +} +.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; }