From ca37d9aa1d30dbc078aa5ca5f68ffe7d5d8cf521 Mon Sep 17 00:00:00 2001 From: Hera Zhao Date: Fri, 10 Apr 2026 15:41:58 +0000 Subject: [PATCH] =?UTF-8?q?UI:=20=E6=89=B9=E9=87=8F=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=B1=95=E5=BC=80=E8=8F=9C=E5=8D=95+=E5=8C=BA=E5=9F=9F?= =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E5=85=A8=E9=80=89=EF=BC=88=E4=BF=9D=E6=8C=81?= =?UTF-8?q?=E5=8E=9F=E5=B8=83=E5=B1=80=EF=BC=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 | 87 ++++++++++++++++++++-------- 1 file changed, 63 insertions(+), 24 deletions(-) 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; }