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;
}