diff --git a/frontend/src/views/RecipeManager.vue b/frontend/src/views/RecipeManager.vue
index 3a00be8..ad6fce4 100644
--- a/frontend/src/views/RecipeManager.vue
+++ b/frontend/src/views/RecipeManager.vue
@@ -65,6 +65,31 @@
+
+
+
+
+ {{ tag }}
+ t !== tag)">×
+
+
+
+ + {{ tag }}
+
+
+
+
+
+
+
+
+
+
@@ -550,6 +575,43 @@ function clearSelection() {
showBatchMenu.value = false
}
+function addBatchTag() {
+ const tag = batchNewTag.value.trim()
+ if (tag && !batchTagsSelected.value.includes(tag)) {
+ batchTagsSelected.value.push(tag)
+ }
+ batchNewTag.value = ''
+}
+
+async function applyBatchTags() {
+ const tags = batchTagsSelected.value
+ if (!tags.length) { ui.showToast('请选择至少一个标签'); return }
+ const pubIds = [...selectedIds]
+ const diaryIds = [...selectedDiaryIds]
+ for (const tagName of tags) {
+ for (const id of pubIds) {
+ const recipe = recipeStore.recipes.find(r => r._id === id)
+ if (recipe && !recipe.tags.includes(tagName)) {
+ recipe.tags.push(tagName)
+ await recipeStore.saveRecipe(recipe)
+ }
+ }
+ for (const id of diaryIds) {
+ const d = diaryStore.userDiary.find(r => r.id === id)
+ if (d) {
+ const dtags = [...(d.tags || [])]
+ if (!dtags.includes(tagName)) {
+ dtags.push(tagName)
+ await diaryStore.updateDiary(id, { ...d, tags: dtags })
+ }
+ }
+ }
+ }
+ showBatchTagPicker.value = false
+ ui.showToast(`已为 ${pubIds.length + diaryIds.length} 个配方添加 ${tags.length} 个标签`)
+ clearSelection()
+}
+
function doBatch(action) {
showBatchMenu.value = false
executeBatchAction(action)
@@ -601,26 +663,10 @@ async function executeBatchAction(action) {
}
ui.showToast(`已删除 ${totalCount} 个配方`)
} else if (action === 'tag') {
- const tagName = await showPrompt('输入要添加的标签:')
- if (!tagName) return
- for (const id of pubIds) {
- const recipe = recipeStore.recipes.find(r => r._id === id)
- if (recipe && !recipe.tags.includes(tagName)) {
- recipe.tags.push(tagName)
- await recipeStore.saveRecipe(recipe)
- }
- }
- for (const id of diaryIds) {
- const d = diaryStore.userDiary.find(r => r.id === id)
- if (d) {
- const tags = [...(d.tags || [])]
- if (!tags.includes(tagName)) {
- tags.push(tagName)
- await diaryStore.updateDiary(id, { ...d, tags })
- }
- }
- }
- ui.showToast(`已为 ${totalCount} 个配方添加标签`)
+ batchTagsSelected.value = []
+ batchNewTag.value = ''
+ showBatchTagPicker.value = true
+ return // don't clear selection yet
} else if (action === 'share_public') {
const ok = await showConfirm(`将 ${diaryIds.length} 个配方分享到公共配方库?`)
if (!ok) return
@@ -976,6 +1022,9 @@ async function saveAllParsed() {
const sharedCount = ref({ adopted: 0, total: 0 })
const previewRecipeIndex = ref(null)
const showBatchMenu = ref(false)
+const showBatchTagPicker = ref(false)
+const batchTagsSelected = ref([])
+const batchNewTag = ref('')
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)
@@ -1641,6 +1690,9 @@ watch(() => recipeStore.recipes, () => {
.batch-menu-btn:hover { border-color: #7ec6a4; color: #4a9d7e; }
.batch-delete { color: #c0392b; border-color: #e8b4b0; }
.batch-delete:hover { background: #fdf0ee; border-color: #c0392b; }
+.batch-tag-picker {
+ padding: 12px; background: #f8faf8; border: 1.5px solid #d4e8d4; border-radius: 10px; margin-bottom: 10px;
+}
.mini-select {
width: 18px; height: 18px; border: 1.5px solid #d4cfc7; border-radius: 4px;
background: #fff; color: transparent; font-size: 11px; cursor: pointer;